diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 146614028..b1a9363ec 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -481,7 +481,7 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[]) } // experimental --project else if (std::strncmp(argv[i], "--project=", 10) == 0) { - _settings->importProject(argv[i]+10); + _settings->project.load(argv[i]+10); } // Report progress @@ -765,7 +765,7 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[]) } // Print error only if we have "real" command and expect files - if (!_exitAfterPrint && _pathnames.empty() && _settings->fileSettings.empty()) { + if (!_exitAfterPrint && _pathnames.empty() && _settings->project.fileSettings.empty()) { PrintMessage("cppcheck: No C or C++ source files found."); return false; } diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 4436afb7f..02c6badd0 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -154,7 +154,7 @@ bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* c FileLister::recursiveAddFiles(_files, Path::toNativeSeparators(*iter), _settings->library.markupExtensions(), matcher); } - if (_files.empty() && settings.fileSettings.empty()) { + if (_files.empty() && settings.project.fileSettings.empty()) { std::cout << "cppcheck: error: could not find or open any of the paths given." << std::endl; if (!ignored.empty()) std::cout << "cppcheck: Maybe all paths were ignored?" << std::endl; @@ -827,11 +827,11 @@ 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); + for (std::list::const_iterator fs = settings.project.fileSettings.begin(); fs != settings.project.fileSettings.end(); ++fs) { + returnValue += cppcheck.check((Project::FileSettings)*fs); ++c; if (!settings.quiet) - reportStatus(c, settings.fileSettings.size(), c, settings.fileSettings.size()); + reportStatus(c, settings.project.fileSettings.size(), c, settings.project.fileSettings.size()); } // second loop to parse all markup files which may not work until all diff --git a/cli/threadexecutor.cpp b/cli/threadexecutor.cpp index 80556d9d2..a6906ee9c 100644 --- a/cli/threadexecutor.cpp +++ b/cli/threadexecutor.cpp @@ -352,11 +352,11 @@ unsigned int ThreadExecutor::check() HANDLE *threadHandles = new HANDLE[_settings.jobs]; _itNextFile = _files.begin(); - _itNextFileSettings = _settings.fileSettings.begin(); + _itNextFileSettings = _settings.project.fileSettings.begin(); _processedFiles = 0; _processedSize = 0; - _totalFiles = _files.size() + _settings.fileSettings.size(); + _totalFiles = _files.size() + _settings.project.fileSettings.size(); _totalFileSize = 0; for (std::map::const_iterator i = _files.begin(); i != _files.end(); ++i) { _totalFileSize += i->second; @@ -417,7 +417,7 @@ unsigned int __stdcall ThreadExecutor::threadProc(void *args) ThreadExecutor *threadExecutor = static_cast(args); std::map::const_iterator &itFile = threadExecutor->_itNextFile; - std::list::const_iterator &itFileSettings = threadExecutor->_itNextFileSettings; + std::list::const_iterator &itFileSettings = threadExecutor->_itNextFileSettings; // guard static members of CppCheck against concurrent access EnterCriticalSection(&threadExecutor->_fileSync); @@ -426,7 +426,7 @@ unsigned int __stdcall ThreadExecutor::threadProc(void *args) fileChecker.settings() = threadExecutor->_settings; for (;;) { - if (itFile == threadExecutor->_files.end() && itFileSettings == threadExecutor->_settings.fileSettings.end()) { + if (itFile == threadExecutor->_files.end() && itFileSettings == threadExecutor->_settings.project.fileSettings.end()) { LeaveCriticalSection(&threadExecutor->_fileSync); break; } @@ -448,7 +448,7 @@ unsigned int __stdcall ThreadExecutor::threadProc(void *args) result += fileChecker.check(file); } } else { // file settings.. - const Settings::FileSettings &fs = *itFileSettings; + const Project::FileSettings &fs = *itFileSettings; ++itFileSettings; LeaveCriticalSection(&threadExecutor->_fileSync); result += fileChecker.check(fs); diff --git a/cli/threadexecutor.h b/cli/threadexecutor.h index 3daf73d17..960e11042 100644 --- a/cli/threadexecutor.h +++ b/cli/threadexecutor.h @@ -23,7 +23,7 @@ #include #include #include "errorlogger.h" -#include "settings.h" // Settings::FileSettings +#include "settings.h" // Project::FileSettings #if (defined(__GNUC__) || defined(__sun)) && !defined(__MINGW32__) #define THREADING_MODEL_FORK @@ -110,7 +110,7 @@ private: std::map _fileContents; std::map::const_iterator _itNextFile; - std::list::const_iterator _itNextFileSettings; + std::list::const_iterator _itNextFileSettings; std::size_t _processedFiles; std::size_t _totalFiles; std::size_t _processedSize; diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 93a5e9aed..da8ba7e7b 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -80,7 +80,7 @@ unsigned int CppCheck::check(const std::string &path, const std::string &content return processFile(path, iss); } -unsigned int CppCheck::check(const Settings::FileSettings &fs) +unsigned int CppCheck::check(const Project::FileSettings &fs) { CppCheck temp(*this, _useGlobalSuppressions); temp._settings.userDefines = fs.defines; diff --git a/lib/cppcheck.h b/lib/cppcheck.h index 8b9e6337f..b4c156608 100644 --- a/lib/cppcheck.h +++ b/lib/cppcheck.h @@ -68,7 +68,7 @@ public: * settings()). */ unsigned int check(const std::string &path); - unsigned int check(const Settings::FileSettings &fs); + unsigned int check(const Project::FileSettings &fs); /** * @brief Check the file. diff --git a/lib/cppcheck.vcxproj b/lib/cppcheck.vcxproj index 983c3bd5e..f3e901425 100644 --- a/lib/cppcheck.vcxproj +++ b/lib/cppcheck.vcxproj @@ -78,7 +78,9 @@ + + @@ -125,7 +127,9 @@ + + diff --git a/lib/cppcheck.vcxproj.filters b/lib/cppcheck.vcxproj.filters index becd8965b..d9daf47c4 100644 --- a/lib/cppcheck.vcxproj.filters +++ b/lib/cppcheck.vcxproj.filters @@ -143,6 +143,12 @@ Source Files + + Source Files + + + Source Files + @@ -286,6 +292,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/lib/platform.cpp b/lib/platform.cpp new file mode 100644 index 000000000..afc8d37e8 --- /dev/null +++ b/lib/platform.cpp @@ -0,0 +1,217 @@ +/* +* Cppcheck - A tool for static C/C++ code analysis +* Copyright (C) 2007-2016 Cppcheck team. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include "tinyxml2.h" + + +Platform::Platform() +{ + // This assumes the code you are checking is for the same architecture this is compiled on. +#if defined(_WIN64) + platform(Win64); +#elif defined(_WIN32) + platform(Win32A); +#else + platform(Native); +#endif +} + + +bool Platform::platform(Platform::PlatformType type) +{ + switch (type) { + case Unspecified: + platformType = type; + sizeof_bool = sizeof(bool); + sizeof_short = sizeof(short); + sizeof_int = sizeof(int); + sizeof_long = sizeof(long); + sizeof_long_long = sizeof(long long); + sizeof_float = sizeof(float); + sizeof_double = sizeof(double); + sizeof_long_double = sizeof(long double); + sizeof_wchar_t = sizeof(wchar_t); + sizeof_size_t = sizeof(std::size_t); + sizeof_pointer = sizeof(void *); + defaultSign = '\0'; + char_bit = 8; + short_bit = char_bit * sizeof_short; + int_bit = char_bit * sizeof_int; + long_bit = char_bit * sizeof_long; + long_long_bit = char_bit * sizeof_long_long; + return true; + case Native: // same as system this code was compile on + platformType = type; + sizeof_bool = sizeof(bool); + sizeof_short = sizeof(short); + sizeof_int = sizeof(int); + sizeof_long = sizeof(long); + sizeof_long_long = sizeof(long long); + sizeof_float = sizeof(float); + sizeof_double = sizeof(double); + sizeof_long_double = sizeof(long double); + sizeof_wchar_t = sizeof(wchar_t); + sizeof_size_t = sizeof(std::size_t); + sizeof_pointer = sizeof(void *); + { + char x = -1; + defaultSign = (x < 0) ? 's' : 'u'; + } + char_bit = 8; + short_bit = char_bit * sizeof_short; + int_bit = char_bit * sizeof_int; + long_bit = char_bit * sizeof_long; + long_long_bit = char_bit * sizeof_long_long; + return true; + case Win32W: + case Win32A: + platformType = type; + sizeof_bool = 1; // 4 in Visual C++ 4.2 + sizeof_short = 2; + sizeof_int = 4; + sizeof_long = 4; + sizeof_long_long = 8; + sizeof_float = 4; + sizeof_double = 8; + sizeof_long_double = 8; + sizeof_wchar_t = 2; + sizeof_size_t = 4; + sizeof_pointer = 4; + defaultSign = '\0'; + char_bit = 8; + short_bit = char_bit * sizeof_short; + int_bit = char_bit * sizeof_int; + long_bit = char_bit * sizeof_long; + long_long_bit = char_bit * sizeof_long_long; + return true; + case Win64: + platformType = type; + sizeof_bool = 1; + sizeof_short = 2; + sizeof_int = 4; + sizeof_long = 4; + sizeof_long_long = 8; + sizeof_float = 4; + sizeof_double = 8; + sizeof_long_double = 8; + sizeof_wchar_t = 2; + sizeof_size_t = 8; + sizeof_pointer = 8; + defaultSign = '\0'; + char_bit = 8; + short_bit = char_bit * sizeof_short; + int_bit = char_bit * sizeof_int; + long_bit = char_bit * sizeof_long; + long_long_bit = char_bit * sizeof_long_long; + return true; + case Unix32: + platformType = type; + sizeof_bool = 1; + sizeof_short = 2; + sizeof_int = 4; + sizeof_long = 4; + sizeof_long_long = 8; + sizeof_float = 4; + sizeof_double = 8; + sizeof_long_double = 12; + sizeof_wchar_t = 4; + sizeof_size_t = 4; + sizeof_pointer = 4; + defaultSign = '\0'; + char_bit = 8; + short_bit = char_bit * sizeof_short; + int_bit = char_bit * sizeof_int; + long_bit = char_bit * sizeof_long; + long_long_bit = char_bit * sizeof_long_long; + return true; + case Unix64: + platformType = type; + sizeof_bool = 1; + sizeof_short = 2; + sizeof_int = 4; + sizeof_long = 8; + sizeof_long_long = 8; + sizeof_float = 4; + sizeof_double = 8; + sizeof_long_double = 16; + sizeof_wchar_t = 4; + sizeof_size_t = 8; + sizeof_pointer = 8; + defaultSign = '\0'; + char_bit = 8; + short_bit = char_bit * sizeof_short; + int_bit = char_bit * sizeof_int; + long_bit = char_bit * sizeof_long; + long_long_bit = char_bit * sizeof_long_long; + return true; + } + + // unsupported platform + return false; +} + +bool Platform::platformFile(const std::string &filename) +{ + // open file.. + tinyxml2::XMLDocument doc; + if (doc.LoadFile(filename.c_str()) != tinyxml2::XML_SUCCESS) + return false; + + const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement(); + + if (!rootnode || std::strcmp(rootnode->Name(), "platform") != 0) + return false; + + for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) { + if (std::strcmp(node->Name(), "default-sign") == 0) + defaultSign = *node->GetText(); + else if (std::strcmp(node->Name(), "char_bit") == 0) + char_bit = std::atoi(node->GetText()); + else if (std::strcmp(node->Name(), "sizeof") == 0) { + for (const tinyxml2::XMLElement *sz = node->FirstChildElement(); sz; sz = sz->NextSiblingElement()) { + if (std::strcmp(node->Name(), "short") == 0) + sizeof_short = std::atoi(node->GetText()); + else if (std::strcmp(node->Name(), "int") == 0) + sizeof_int = std::atoi(node->GetText()); + else if (std::strcmp(node->Name(), "long") == 0) + sizeof_long = std::atoi(node->GetText()); + else if (std::strcmp(node->Name(), "long-long") == 0) + sizeof_long_long = std::atoi(node->GetText()); + else if (std::strcmp(node->Name(), "float") == 0) + sizeof_float = std::atoi(node->GetText()); + else if (std::strcmp(node->Name(), "double") == 0) + sizeof_double = std::atoi(node->GetText()); + else if (std::strcmp(node->Name(), "long-double") == 0) + sizeof_long_double = std::atoi(node->GetText()); + else if (std::strcmp(node->Name(), "pointer") == 0) + sizeof_pointer = std::atoi(node->GetText()); + else if (std::strcmp(node->Name(), "size_t") == 0) + sizeof_size_t = std::atoi(node->GetText()); + else if (std::strcmp(node->Name(), "wchar_t") == 0) + sizeof_wchar_t = std::atoi(node->GetText()); + } + } + } + + short_bit = char_bit * sizeof_short; + int_bit = char_bit * sizeof_int; + long_bit = char_bit * sizeof_long; + long_long_bit = char_bit * sizeof_long_long; + + return true; +} diff --git a/lib/platform.h b/lib/platform.h new file mode 100644 index 000000000..93d6022bf --- /dev/null +++ b/lib/platform.h @@ -0,0 +1,109 @@ +/* +* Cppcheck - A tool for static C/C++ code analysis +* Copyright (C) 2007-2016 Cppcheck team. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +//--------------------------------------------------------------------------- +#ifndef platformH +#define platformH +//--------------------------------------------------------------------------- + +#include + +/// @addtogroup Core +/// @{ + +/** +* @brief This is just a container for general settings so that we don't need +* to pass individual values to functions or constructors now or in the +* future when we might have even more detailed settings. +*/ +struct CPPCHECKLIB Platform { +public: + Platform(); + virtual ~Platform(){} + + unsigned int char_bit; /// bits in char + unsigned int short_bit; /// bits in short + unsigned int int_bit; /// bits in int + unsigned int long_bit; /// bits in long + unsigned int long_long_bit; /// bits in long long + + /** size of standard types */ + unsigned int sizeof_bool; + unsigned int sizeof_short; + unsigned int sizeof_int; + unsigned int sizeof_long; + unsigned int sizeof_long_long; + unsigned int sizeof_float; + unsigned int sizeof_double; + unsigned int sizeof_long_double; + unsigned int sizeof_wchar_t; + unsigned int sizeof_size_t; + unsigned int sizeof_pointer; + + char defaultSign; // unsigned:'u', signed:'s', unknown:'\0' + + enum PlatformType { + Unspecified, // No platform specified + Native, // whatever system this code was compiled on + Win32A, + Win32W, + Win64, + Unix32, + Unix64 + }; + + /** platform type */ + PlatformType platformType; + + /** set the platform type for predefined platforms */ + bool platform(PlatformType type); + + /** set the platform type for user specified platforms */ + bool platformFile(const std::string &filename); + + /** + * @brief Returns true if platform type is Windows + * @return true if Windows platform type. + */ + bool isWindowsPlatform() const { + return platformType == Win32A || + platformType == Win32W || + platformType == Win64; + } + + const char *platformString() const { + switch (platformType) { + case Unix32: + return "unix32"; + case Unix64: + return "unix64"; + case Win32A: + return "win32A"; + case Win32W: + return "win32W"; + case Win64: + return "win64"; + default: + return "unknown"; + } + } +}; + +/// @} +//--------------------------------------------------------------------------- +#endif // platformH diff --git a/lib/project.cpp b/lib/project.cpp new file mode 100644 index 000000000..9ca014d07 --- /dev/null +++ b/lib/project.cpp @@ -0,0 +1,204 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2016 Cppcheck team. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "project.h" +#include "path.h" +#include "tokenlist.h" +#include "tinyxml2.h" +#include + +void Project::load(const std::string &filename) { + std::ifstream fin(filename); + if (!fin.is_open()) + return; + if (filename == "compile_commands.json") { + loadCompileCommands(fin); + } else if (filename.find(".vcxproj") != std::string::npos) { + loadVcxproj(filename); + } +} + +void Project::loadCompileCommands(std::istream &istr) { + std::map values; + + Settings settings; + TokenList tokenList(&settings); + tokenList.createTokens(istr); + for (const Token *tok = tokenList.front(); tok; tok = tok->next()) { + if (Token::Match(tok, "%str% : %str% [,}]")) { + std::string key = tok->str(); + std::string value = tok->strAt(2); + values[key.substr(1, key.size() - 2U)] = value.substr(1, value.size() - 2U); + } + + else if (tok->str() == "}") { + if (!values["file"].empty() && !values["command"].empty()) { + struct FileSettings fs; + fs.filename = Path::fromNativeSeparators(values["file"]); + std::string command = values["command"]; + std::string::size_type pos = 0; + while (std::string::npos != (pos = command.find(" ",pos))) { + pos++; + if (pos >= command.size()) + break; + if (command[pos] != '/' && command[pos] != '-') + continue; + pos++; + if (pos >= command.size()) + break; + char F = command[pos++]; + std::string fval; + while (pos < command.size() && command[pos] != ' ') + fval += command[pos++]; + if (F=='D') + fs.defines += fval + ";"; + else if (F=='U') + fs.undefs.insert(fval); + else if (F=='I') + fs.includePaths.push_back(fval); + } + fileSettings.push_back(fs); + } + values.clear(); + } + } +} + +namespace { + struct ProjectConfiguration { + ProjectConfiguration(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) { + const char *condAttr = idg->Attribute("Condition"); + if (condAttr) + condition = condAttr; + 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 ProjectConfiguration &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 Project::loadVcxproj(const std::string &filename) +{ + std::list projectConfigurationList; + 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"), "ProjectConfigurations") == 0) { + for (const tinyxml2::XMLElement *cfg = node->FirstChildElement(); cfg; cfg = cfg->NextSiblingElement()) { + if (std::strcmp(cfg->Name(), "ProjectConfiguration") == 0) + projectConfigurationList.push_back(ProjectConfiguration(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)); + } + } + + for (std::list::const_iterator c = compileList.begin(); c != compileList.end(); ++c) { + for (std::list::const_iterator p = projectConfigurationList.begin(); p != projectConfigurationList.end(); ++p) { + for (std::list::const_iterator i = itemDefinitionGroupList.begin(); i != itemDefinitionGroupList.end(); ++i) { + if (!i->conditionIsTrue(*p)) + continue; + FileSettings fs; + fs.filename = Path::simplifyPath(Path::getPathFromFilename(filename) + *c); + fs.defines = i->preprocessorDefinitions; + fs.includePaths = toStringList(i->additionalIncludePaths); + if (p->platform == "Win32") + fs.platformType = Settings::Win32W; + else if (p->platform == "x64") + fs.platformType = Settings::Win64; + fileSettings.push_back(fs); + } + } + } +} diff --git a/lib/project.h b/lib/project.h new file mode 100644 index 000000000..71a7e0bbd --- /dev/null +++ b/lib/project.h @@ -0,0 +1,62 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2016 Cppcheck team. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//--------------------------------------------------------------------------- +#ifndef projectH +#define projectH +//--------------------------------------------------------------------------- + +#include +#include +#include +#include "config.h" +#include "platform.h" + +/// @addtogroup Core +/// @{ + + +/** + * @brief This is just a container for general settings so that we don't need + * to pass individual values to functions or constructors now or in the + * future when we might have even more detailed settings. + */ +class CPPCHECKLIB Project { +public: + + + /** File */ + struct FileSettings { + FileSettings() : platformType(Platform::Unspecified) {} + std::string filename; + std::string defines; + std::set undefs; + std::list includePaths; + Platform::PlatformType platformType; + }; + std::list fileSettings; + + void load(const std::string &filename); +private: + void loadCompileCommands(std::istream &istr); + void loadVcxproj(const std::string &filename); +}; + +/// @} +//--------------------------------------------------------------------------- +#endif // projectH diff --git a/lib/settings.cpp b/lib/settings.cpp index fe777d55c..4f80f91d3 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -19,7 +19,6 @@ #include "settings.h" #include "preprocessor.h" // Preprocessor #include "utils.h" -#include "tinyxml2.h" #include "path.h" #include "tokenlist.h" @@ -53,14 +52,6 @@ Settings::Settings() checkConfiguration(false), checkLibrary(false) { - // This assumes the code you are checking is for the same architecture this is compiled on. -#if defined(_WIN64) - platform(Win64); -#elif defined(_WIN32) - platform(Win32A); -#else - platform(Native); -#endif } namespace { @@ -139,367 +130,3 @@ const std::string &Settings::append() const { return _append; } - -bool Settings::platform(PlatformType type) -{ - switch (type) { - case Unspecified: - platformType = type; - sizeof_bool = sizeof(bool); - sizeof_short = sizeof(short); - sizeof_int = sizeof(int); - sizeof_long = sizeof(long); - sizeof_long_long = sizeof(long long); - sizeof_float = sizeof(float); - sizeof_double = sizeof(double); - sizeof_long_double = sizeof(long double); - sizeof_wchar_t = sizeof(wchar_t); - sizeof_size_t = sizeof(std::size_t); - sizeof_pointer = sizeof(void *); - defaultSign = '\0'; - char_bit = 8; - short_bit = char_bit * sizeof_short; - int_bit = char_bit * sizeof_int; - long_bit = char_bit * sizeof_long; - long_long_bit = char_bit * sizeof_long_long; - return true; - case Native: // same as system this code was compile on - platformType = type; - sizeof_bool = sizeof(bool); - sizeof_short = sizeof(short); - sizeof_int = sizeof(int); - sizeof_long = sizeof(long); - sizeof_long_long = sizeof(long long); - sizeof_float = sizeof(float); - sizeof_double = sizeof(double); - sizeof_long_double = sizeof(long double); - sizeof_wchar_t = sizeof(wchar_t); - sizeof_size_t = sizeof(std::size_t); - sizeof_pointer = sizeof(void *); - { - char x = -1; - defaultSign = (x < 0) ? 's' : 'u'; - } - char_bit = 8; - short_bit = char_bit * sizeof_short; - int_bit = char_bit * sizeof_int; - long_bit = char_bit * sizeof_long; - long_long_bit = char_bit * sizeof_long_long; - return true; - case Win32W: - case Win32A: - platformType = type; - sizeof_bool = 1; // 4 in Visual C++ 4.2 - sizeof_short = 2; - sizeof_int = 4; - sizeof_long = 4; - sizeof_long_long = 8; - sizeof_float = 4; - sizeof_double = 8; - sizeof_long_double = 8; - sizeof_wchar_t = 2; - sizeof_size_t = 4; - sizeof_pointer = 4; - defaultSign = '\0'; - char_bit = 8; - short_bit = char_bit * sizeof_short; - int_bit = char_bit * sizeof_int; - long_bit = char_bit * sizeof_long; - long_long_bit = char_bit * sizeof_long_long; - return true; - case Win64: - platformType = type; - sizeof_bool = 1; - sizeof_short = 2; - sizeof_int = 4; - sizeof_long = 4; - sizeof_long_long = 8; - sizeof_float = 4; - sizeof_double = 8; - sizeof_long_double = 8; - sizeof_wchar_t = 2; - sizeof_size_t = 8; - sizeof_pointer = 8; - defaultSign = '\0'; - char_bit = 8; - short_bit = char_bit * sizeof_short; - int_bit = char_bit * sizeof_int; - long_bit = char_bit * sizeof_long; - long_long_bit = char_bit * sizeof_long_long; - return true; - case Unix32: - platformType = type; - sizeof_bool = 1; - sizeof_short = 2; - sizeof_int = 4; - sizeof_long = 4; - sizeof_long_long = 8; - sizeof_float = 4; - sizeof_double = 8; - sizeof_long_double = 12; - sizeof_wchar_t = 4; - sizeof_size_t = 4; - sizeof_pointer = 4; - defaultSign = '\0'; - char_bit = 8; - short_bit = char_bit * sizeof_short; - int_bit = char_bit * sizeof_int; - long_bit = char_bit * sizeof_long; - long_long_bit = char_bit * sizeof_long_long; - return true; - case Unix64: - platformType = type; - sizeof_bool = 1; - sizeof_short = 2; - sizeof_int = 4; - sizeof_long = 8; - sizeof_long_long = 8; - sizeof_float = 4; - sizeof_double = 8; - sizeof_long_double = 16; - sizeof_wchar_t = 4; - sizeof_size_t = 8; - sizeof_pointer = 8; - defaultSign = '\0'; - char_bit = 8; - short_bit = char_bit * sizeof_short; - int_bit = char_bit * sizeof_int; - long_bit = char_bit * sizeof_long; - long_long_bit = char_bit * sizeof_long_long; - return true; - } - - // unsupported platform - return false; -} - -bool Settings::platformFile(const std::string &filename) -{ - // open file.. - tinyxml2::XMLDocument doc; - if (doc.LoadFile(filename.c_str()) != tinyxml2::XML_SUCCESS) - return false; - - const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement(); - - if (!rootnode || std::strcmp(rootnode->Name(),"platform") != 0) - return false; - - for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) { - if (std::strcmp(node->Name(), "default-sign") == 0) - defaultSign = *node->GetText(); - else if (std::strcmp(node->Name(), "char_bit") == 0) - char_bit = std::atoi(node->GetText()); - else if (std::strcmp(node->Name(), "sizeof") == 0) { - for (const tinyxml2::XMLElement *sz = node->FirstChildElement(); sz; sz = sz->NextSiblingElement()) { - if (std::strcmp(node->Name(), "short") == 0) - sizeof_short = std::atoi(node->GetText()); - else if (std::strcmp(node->Name(), "int") == 0) - sizeof_int = std::atoi(node->GetText()); - else if (std::strcmp(node->Name(), "long") == 0) - sizeof_long = std::atoi(node->GetText()); - else if (std::strcmp(node->Name(), "long-long") == 0) - sizeof_long_long = std::atoi(node->GetText()); - else if (std::strcmp(node->Name(), "float") == 0) - sizeof_float = std::atoi(node->GetText()); - else if (std::strcmp(node->Name(), "double") == 0) - sizeof_double = std::atoi(node->GetText()); - else if (std::strcmp(node->Name(), "long-double") == 0) - sizeof_long_double = std::atoi(node->GetText()); - else if (std::strcmp(node->Name(), "pointer") == 0) - sizeof_pointer = std::atoi(node->GetText()); - else if (std::strcmp(node->Name(), "size_t") == 0) - sizeof_size_t = std::atoi(node->GetText()); - else if (std::strcmp(node->Name(), "wchar_t") == 0) - sizeof_wchar_t = std::atoi(node->GetText()); - } - } - } - - short_bit = char_bit * sizeof_short; - int_bit = char_bit * sizeof_int; - long_bit = char_bit * sizeof_long; - long_long_bit = char_bit * sizeof_long_long; - - return true; -} - -void Settings::importProject(const std::string &filename) { - std::ifstream fin(filename); - if (!fin.is_open()) - return; - if (filename == "compile_commands.json") { - importCompileCommands(fin); - } else if (filename.find(".vcxproj") != std::string::npos) { - importVcxproj(filename); - } -} - -void Settings::importCompileCommands(std::istream &istr) { - std::map values; - - TokenList tokenList(this); - tokenList.createTokens(istr); - for (const Token *tok = tokenList.front(); tok; tok = tok->next()) { - if (Token::Match(tok, "%str% : %str% [,}]")) { - std::string key = tok->str(); - std::string value = tok->strAt(2); - values[key.substr(1, key.size() - 2U)] = value.substr(1, value.size() - 2U); - } - - else if (tok->str() == "}") { - if (!values["file"].empty() && !values["command"].empty()) { - struct FileSettings fs; - fs.filename = Path::fromNativeSeparators(values["file"]); - std::string command = values["command"]; - std::string::size_type pos = 0; - while (std::string::npos != (pos = command.find(" ",pos))) { - pos++; - if (pos >= command.size()) - break; - if (command[pos] != '/' && command[pos] != '-') - continue; - pos++; - if (pos >= command.size()) - break; - char F = command[pos++]; - std::string fval; - while (pos < command.size() && command[pos] != ' ') - fval += command[pos++]; - if (F=='D') - fs.defines += fval + ";"; - else if (F=='U') - fs.undefs.insert(fval); - else if (F=='I') - fs.includePaths.push_back(fval); - } - fileSettings.push_back(fs); - } - values.clear(); - } - } -} - -namespace { - struct ProjectConfiguration { - ProjectConfiguration(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) { - const char *condAttr = idg->Attribute("Condition"); - if (condAttr) - condition = condAttr; - 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 ProjectConfiguration &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 projectConfigurationList; - 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"), "ProjectConfigurations") == 0) { - for (const tinyxml2::XMLElement *cfg = node->FirstChildElement(); cfg; cfg = cfg->NextSiblingElement()) { - if (std::strcmp(cfg->Name(), "ProjectConfiguration") == 0) - projectConfigurationList.push_back(ProjectConfiguration(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)); - } - } - - for (std::list::const_iterator c = compileList.begin(); c != compileList.end(); ++c) { - for (std::list::const_iterator p = projectConfigurationList.begin(); p != projectConfigurationList.end(); ++p) { - for (std::list::const_iterator i = itemDefinitionGroupList.begin(); i != itemDefinitionGroupList.end(); ++i) { - if (!i->conditionIsTrue(*p)) - continue; - FileSettings fs; - fs.filename = Path::simplifyPath(Path::getPathFromFilename(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 371619c09..797a9c8fa 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -27,6 +27,8 @@ #include #include "config.h" #include "library.h" +#include "platform.h" +#include "project.h" #include "suppressions.h" #include "standards.h" #include "errorlogger.h" @@ -35,13 +37,12 @@ /// @addtogroup Core /// @{ - /** * @brief This is just a container for general settings so that we don't need * to pass individual values to functions or constructors now or in the * future when we might have even more detailed settings. */ -class CPPCHECKLIB Settings { +class CPPCHECKLIB Settings : public Platform { private: /** @brief Code to append in the checks */ std::string _append; @@ -243,72 +244,7 @@ public: /** Struct contains standards settings */ Standards standards; - unsigned int char_bit; /// bits in char - unsigned int short_bit; /// bits in short - unsigned int int_bit; /// bits in int - unsigned int long_bit; /// bits in long - unsigned int long_long_bit; /// bits in long long - - /** size of standard types */ - unsigned int sizeof_bool; - unsigned int sizeof_short; - unsigned int sizeof_int; - unsigned int sizeof_long; - unsigned int sizeof_long_long; - unsigned int sizeof_float; - unsigned int sizeof_double; - unsigned int sizeof_long_double; - unsigned int sizeof_wchar_t; - unsigned int sizeof_size_t; - unsigned int sizeof_pointer; - - char defaultSign; // unsigned:'u', signed:'s', unknown:'\0' - - enum PlatformType { - Unspecified, // No platform specified - Native, // whatever system this code was compiled on - Win32A, - Win32W, - Win64, - Unix32, - Unix64 - }; - - /** platform type */ - PlatformType platformType; - - /** set the platform type for predefined platforms */ - bool platform(PlatformType type); - - /** set the platform type for user specified platforms */ - bool platformFile(const std::string &filename); - - /** - * @brief Returns true if platform type is Windows - * @return true if Windows platform type. - */ - bool isWindowsPlatform() const { - return platformType == Win32A || - platformType == Win32W || - platformType == Win64; - } - - const char *platformString() const { - switch (platformType) { - case Unix32: - return "unix32"; - case Unix64: - return "unix64"; - case Win32A: - return "win32A"; - case Win32W: - return "win32W"; - case Win64: - return "win64"; - default: - return "unknown"; - } - } + Project project; /** * @brief return true if a file is to be excluded from configuration checking @@ -322,22 +258,6 @@ public: } return false; } - - /** File settings */ - struct FileSettings { - FileSettings() : platformType(Unspecified) {} - std::string filename; - std::string defines; - 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); }; /// @}