From e0f4ce9358534b2d352c721b791536248c84259d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 7 Aug 2016 13:55:27 +0200 Subject: [PATCH] vs --- cli/cppcheckexecutor.cpp | 9 +++ lib/cppcheck.cpp | 12 ++++ lib/cppcheck.h | 1 + lib/settings.cpp | 130 ++++++++++++++++++++++++++++++++++++++- lib/settings.h | 7 ++- 5 files changed, 155 insertions(+), 4 deletions(-) diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 9334a1d0e..4436afb7f 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -825,6 +825,15 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck, int /*argc*/, const cha } } + // filesettings + c = 0; + for (std::list::const_iterator fs = settings.fileSettings.begin(); fs != settings.fileSettings.end(); ++fs) { + returnValue += cppcheck.check(*fs); + ++c; + if (!settings.quiet) + reportStatus(c, settings.fileSettings.size(), c, settings.fileSettings.size()); + } + // second loop to parse all markup files which may not work until all // c/cpp files have been parsed and checked for (std::map::const_iterator i = _files.begin(); i != _files.end(); ++i) { diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index aaf5f9810..93a5e9aed 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -80,6 +80,18 @@ unsigned int CppCheck::check(const std::string &path, const std::string &content return processFile(path, iss); } +unsigned int CppCheck::check(const Settings::FileSettings &fs) +{ + CppCheck temp(*this, _useGlobalSuppressions); + temp._settings.userDefines = fs.defines; + temp._settings.userIncludes = fs.includePaths; + // TODO: temp._settings.userUndefs = fs.undefs; + if (fs.platformType != Settings::Unspecified) { + temp._settings.platformType = fs.platformType; + } + return temp.check(fs.filename); +} + unsigned int CppCheck::processFile(const std::string& filename, std::istream& fileStream) { exitcode = 0; diff --git a/lib/cppcheck.h b/lib/cppcheck.h index 380ba713d..8b9e6337f 100644 --- a/lib/cppcheck.h +++ b/lib/cppcheck.h @@ -68,6 +68,7 @@ public: * settings()). */ unsigned int check(const std::string &path); + unsigned int check(const Settings::FileSettings &fs); /** * @brief Check the file. diff --git a/lib/settings.cpp b/lib/settings.cpp index 53486dc83..e56952a03 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -330,6 +330,8 @@ void Settings::importProject(const std::string &filename) { return; if (filename == "compile_commands.json") { importCompileCommands(fin); + } else if (filename.find(".vcxproj") != std::string::npos) { + importVcxproj(filename); } } @@ -367,9 +369,9 @@ void Settings::importCompileCommands(std::istream &istr) { if (F=='D') fs.defines += fval + ";"; else if (F=='U') - fs.undefs += fval + ";"; + fs.undefs.insert(fval); else if (F=='I') - fs.includes += fval + ";"; + fs.includePaths.push_back(fval); } fileSettings.push_back(fs); } @@ -378,3 +380,127 @@ void Settings::importCompileCommands(std::istream &istr) { } } +namespace { + struct ProgramConfiguration { + ProgramConfiguration(const tinyxml2::XMLElement *cfg) { + for (const tinyxml2::XMLElement *e = cfg->FirstChildElement(); e; e = e->NextSiblingElement()) { + if (std::strcmp(e->Name(),"Configuration")==0) + configuration = e->GetText(); + else if (std::strcmp(e->Name(),"Platform")==0) + platform = e->GetText(); + } + } + std::string configuration; + std::string platform; + }; + + struct ItemDefinitionGroup { + ItemDefinitionGroup(const tinyxml2::XMLElement *idg) { + condition = idg->Attribute("condition"); + for (const tinyxml2::XMLElement *e1 = idg->FirstChildElement(); e1; e1 = e1->NextSiblingElement()) { + if (std::strcmp(e1->Name(), "ClCompile") != 0) + continue; + for (const tinyxml2::XMLElement *e = e1->FirstChildElement(); e; e = e->NextSiblingElement()) { + if (std::strcmp(e->Name(), "PreprocessorDefinitions") == 0) + preprocessorDefinitions = e->GetText(); + else if (std::strcmp(e->Name(), "AdditionalIncludeDirectories") == 0) + additionalIncludePaths = e->GetText(); + } + } + } + bool conditionIsTrue(const ProgramConfiguration &p) const { + std::string c = condition; + std::string::size_type pos = 0; + while ((pos = c.find("$(Configuration)")) != std::string::npos) { + c.erase(pos,16); + c.insert(pos,p.configuration); + } + while ((pos = c.find("$(Platform)")) != std::string::npos) { + c.erase(pos, 11); + c.insert(pos, p.platform); + } + // TODO : Better evaluation + Settings s; + std::istringstream istr(c); + TokenList tokens(&s); + tokens.createTokens(istr); + tokens.createAst(); + for (const Token *tok = tokens.front(); tok; tok = tok->next()) { + if (tok->str() == "==" && tok->astOperand1() && tok->astOperand2() && tok->astOperand1()->str() == tok->astOperand2()->str()) + return true; + } + return false; + } + std::string condition; + std::string preprocessorDefinitions; + std::string additionalIncludePaths; + }; +}; + +static std::list toStringList(const std::string &s) { + std::list ret; + std::string::size_type pos1 = 0; + std::string::size_type pos2; + while ((pos2 = s.find(";",pos1)) != std::string::npos) { + ret.push_back(s.substr(pos1, pos2-pos1)); + pos1 = pos2 + 1; + if (pos1 >= s.size()) + break; + } + if (pos1 < s.size()) + ret.push_back(s.substr(pos1)); + return ret; +} + +void Settings::importVcxproj(const std::string &filename) +{ + std::list programConfigurationList; + std::list compileList; + std::list itemDefinitionGroupList; + + tinyxml2::XMLDocument doc; + tinyxml2::XMLError error = doc.LoadFile(filename.c_str()); + if (error != tinyxml2::XML_SUCCESS) + return; + const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement(); + if (rootnode == nullptr) + return; + for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) { + if (std::strcmp(node->Name(), "ItemGroup") == 0) { + if (node->Attribute("Label") && std::strcmp(node->Attribute("Label"), "ProgramConfigurations") == 0) { + for (const tinyxml2::XMLElement *cfg = node->FirstChildElement(); cfg; cfg = cfg->NextSiblingElement()) { + if (std::strcmp(cfg->Name(), "ProgramConfiguration") == 0) + programConfigurationList.push_back(ProgramConfiguration(cfg)); + } + } else { + for (const tinyxml2::XMLElement *e = node->FirstChildElement(); e; e = e->NextSiblingElement()) { + if (std::strcmp(e->Name(), "clCompile") == 0) + compileList.push_back(e->Attribute("Include")); + } + } + } else if (std::strcmp(node->Name(), "ItemDefinitionGroup") == 0) { + itemDefinitionGroupList.push_back(ItemDefinitionGroup(node)); + } + } + + //std::list programConfigurationList; + //std::list compileList; + //std::list itemDefinitionGroupList; + for (std::list::const_iterator c = compileList.begin(); c != compileList.end(); ++c) { + for (std::list::const_iterator p = programConfigurationList.begin(); p != programConfigurationList.end(); ++p) { + for (std::list::const_iterator i = itemDefinitionGroupList.begin(); i != itemDefinitionGroupList.end(); ++i) { + if (!i->conditionIsTrue(*p)) + continue; + FileSettings fs; + fs.filename = *c; + fs.defines = i->preprocessorDefinitions; + fs.includePaths = toStringList(i->additionalIncludePaths); + if (p->platform == "Win32") + fs.platformType = Win32W; + else if (p->platform == "x64") + fs.platformType = Win64; + fileSettings.push_back(fs); + } + } + } +} diff --git a/lib/settings.h b/lib/settings.h index dd6b43c7f..371619c09 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -325,16 +325,19 @@ public: /** File settings */ struct FileSettings { + FileSettings() : platformType(Unspecified) {} std::string filename; std::string defines; - std::string undefs; - std::string includes; + std::set undefs; + std::list includePaths; + PlatformType platformType; }; std::list fileSettings; void importProject(const std::string &filename); private: void importCompileCommands(std::istream &istr); + void importVcxproj(const std::string &filename); }; /// @}