diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 4c1abf91a..2ac00c57e 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -895,7 +895,10 @@ Settings MainWindow::getCppcheckSettings() result.maxCtuDepth = mProjectFile->getMaxCtuDepth(); result.checkHeaders = mProjectFile->getCheckHeaders(); result.checkUnusedTemplates = mProjectFile->getCheckUnusedTemplates(); - result.allFunctionsAreSafe = mProjectFile->getCheckAllFunctionParameterValues(); + result.safeChecks.classes = mProjectFile->getSafeChecks().classes; + result.safeChecks.externalFunctions = mProjectFile->getSafeChecks().externalFunctions; + result.safeChecks.internalFunctions = mProjectFile->getSafeChecks().internalFunctions; + result.safeChecks.externalVariables = mProjectFile->getSafeChecks().externalVariables; foreach (QString s, mProjectFile->getCheckUnknownFunctionReturn()) result.checkUnknownFunctionReturn.insert(s.toStdString()); } diff --git a/gui/projectfile.cpp b/gui/projectfile.cpp index 3ebeea2ec..b15db68a4 100644 --- a/gui/projectfile.cpp +++ b/gui/projectfile.cpp @@ -26,6 +26,7 @@ #include "common.h" #include "path.h" +#include "settings.h" static const char ProjectElementName[] = "project"; static const char ProjectVersionAttrib[] = "version"; @@ -67,7 +68,6 @@ static const char CheckHeadersElementName[] = "check-headers"; static const char CheckUnusedTemplatesElementName[] = "check-unused-templates"; static const char MaxCtuDepthElementName[] = "max-ctu-depth"; static const char CheckUnknownFunctionReturn[] = "check-unknown-function-return-values"; -static const char CheckAllFunctionParameterValues[] = "check-all-function-parameter-values"; static const char Name[] = "name"; ProjectFile::ProjectFile(QObject *parent) : @@ -104,8 +104,8 @@ void ProjectFile::clear() mCheckHeaders = true; mCheckUnusedTemplates = false; mMaxCtuDepth = 10; - mCheckAllFunctionParameterValues = false; mCheckUnknownFunctionReturn.clear(); + mSafeChecks.clear(); } bool ProjectFile::read(const QString &filename) @@ -128,77 +128,81 @@ bool ProjectFile::read(const QString &filename) if (xmlReader.name() == ProjectElementName) { insideProject = true; projectTagFound = true; + break; } + if (!insideProject) + break; + // Read root path from inside project element - if (insideProject && xmlReader.name() == RootPathName) + if (xmlReader.name() == RootPathName) readRootPath(xmlReader); // Read root path from inside project element - if (insideProject && xmlReader.name() == BuildDirElementName) + if (xmlReader.name() == BuildDirElementName) readBuildDir(xmlReader); // Find paths to check from inside project element - if (insideProject && xmlReader.name() == PathsElementName) + if (xmlReader.name() == PathsElementName) readCheckPaths(xmlReader); - if (insideProject && xmlReader.name() == ImportProjectElementName) + if (xmlReader.name() == ImportProjectElementName) readImportProject(xmlReader); - if (insideProject && xmlReader.name() == AnalyzeAllVsConfigsElementName) + if (xmlReader.name() == AnalyzeAllVsConfigsElementName) mAnalyzeAllVsConfigs = readBool(xmlReader); - if (insideProject && xmlReader.name() == CheckHeadersElementName) + if (xmlReader.name() == CheckHeadersElementName) mCheckHeaders = readBool(xmlReader); - if (insideProject && xmlReader.name() == CheckUnusedTemplatesElementName) + if (xmlReader.name() == CheckUnusedTemplatesElementName) mCheckUnusedTemplates = readBool(xmlReader); // Find include directory from inside project element - if (insideProject && xmlReader.name() == IncludeDirElementName) + if (xmlReader.name() == IncludeDirElementName) readIncludeDirs(xmlReader); // Find preprocessor define from inside project element - if (insideProject && xmlReader.name() == DefinesElementName) + if (xmlReader.name() == DefinesElementName) readDefines(xmlReader); // Find preprocessor define from inside project element - if (insideProject && xmlReader.name() == UndefinesElementName) + if (xmlReader.name() == UndefinesElementName) readStringList(mUndefines, xmlReader, UndefineName); // Find exclude list from inside project element - if (insideProject && xmlReader.name() == ExcludeElementName) + if (xmlReader.name() == ExcludeElementName) readExcludes(xmlReader); // Find ignore list from inside project element // These are read for compatibility - if (insideProject && xmlReader.name() == IgnoreElementName) + if (xmlReader.name() == IgnoreElementName) readExcludes(xmlReader); // Find libraries list from inside project element - if (insideProject && xmlReader.name() == LibrariesElementName) + if (xmlReader.name() == LibrariesElementName) readStringList(mLibraries, xmlReader,LibraryElementName); - if (insideProject && xmlReader.name() == PlatformElementName) + if (xmlReader.name() == PlatformElementName) readPlatform(xmlReader); // Find suppressions list from inside project element - if (insideProject && xmlReader.name() == SuppressionsElementName) + if (xmlReader.name() == SuppressionsElementName) readSuppressions(xmlReader); // Unknown function return values - if (insideProject && xmlReader.name() == CheckUnknownFunctionReturn) + if (xmlReader.name() == CheckUnknownFunctionReturn) readStringList(mCheckUnknownFunctionReturn, xmlReader, Name); // check all function parameter values - if (insideProject && xmlReader.name() == CheckAllFunctionParameterValues) - mCheckAllFunctionParameterValues = true; + if (xmlReader.name() == Settings::SafeChecks::XmlRootName) + mSafeChecks.loadFromXml(xmlReader); // Addons - if (insideProject && xmlReader.name() == AddonsElementName) + if (xmlReader.name() == AddonsElementName) readStringList(mAddons, xmlReader, AddonElementName); // Tools - if (insideProject && xmlReader.name() == ToolsElementName) { + if (xmlReader.name() == ToolsElementName) { QStringList tools; readStringList(tools, xmlReader, ToolElementName); mClangAnalyzer = tools.contains(CLANG_ANALYZER); @@ -796,10 +800,7 @@ bool ProjectFile::write(const QString &filename) CheckUnknownFunctionReturn, Name); - if (mCheckAllFunctionParameterValues) { - xmlWriter.writeStartElement(CheckAllFunctionParameterValues); - xmlWriter.writeEndElement(); - } + mSafeChecks.saveToXml(xmlWriter); writeStringList(xmlWriter, mAddons, @@ -854,3 +855,67 @@ QStringList ProjectFile::getAddonsAndTools() const ret << CLANG_TIDY; return ret; } + +void ProjectFile::SafeChecks::loadFromXml(QXmlStreamReader &xmlReader) +{ + classes = externalFunctions = internalFunctions = externalVariables = false; + + int level = 0; + + do { + const QXmlStreamReader::TokenType type = xmlReader.readNext(); + switch (type) { + case QXmlStreamReader::StartElement: + ++level; + if (xmlReader.name() == Settings::SafeChecks::XmlClasses) + classes = true; + else if (xmlReader.name() == Settings::SafeChecks::XmlExternalFunctions) + externalFunctions = true; + else if (xmlReader.name() == Settings::SafeChecks::XmlInternalFunctions) + internalFunctions = true; + else if (xmlReader.name() == Settings::SafeChecks::XmlExternalVariables) + externalVariables = true; + break; + case QXmlStreamReader::EndElement: + if (level <= 0) + return; + level--; + break; + // Not handled + case QXmlStreamReader::Characters: + case QXmlStreamReader::NoToken: + case QXmlStreamReader::Invalid: + case QXmlStreamReader::StartDocument: + case QXmlStreamReader::EndDocument: + case QXmlStreamReader::Comment: + case QXmlStreamReader::DTD: + case QXmlStreamReader::EntityReference: + case QXmlStreamReader::ProcessingInstruction: + break; + } + } while (1); +} + +void ProjectFile::SafeChecks::saveToXml(QXmlStreamWriter &xmlWriter) const +{ + if (!classes && !externalFunctions && !internalFunctions && !externalVariables) + return; + xmlWriter.writeStartElement(Settings::SafeChecks::XmlRootName); + if (classes) { + xmlWriter.writeStartElement(Settings::SafeChecks::XmlClasses); + xmlWriter.writeEndElement(); + } + if (externalFunctions) { + xmlWriter.writeStartElement(Settings::SafeChecks::XmlExternalFunctions); + xmlWriter.writeEndElement(); + } + if (internalFunctions) { + xmlWriter.writeStartElement(Settings::SafeChecks::XmlInternalFunctions); + xmlWriter.writeEndElement(); + } + if (externalVariables) { + xmlWriter.writeStartElement(Settings::SafeChecks::XmlExternalVariables); + xmlWriter.writeEndElement(); + } + xmlWriter.writeEndElement(); +} diff --git a/gui/projectfile.h b/gui/projectfile.h index 0ad9a321a..4fb0b98fb 100644 --- a/gui/projectfile.h +++ b/gui/projectfile.h @@ -300,12 +300,52 @@ public: mFilename = filename; } - /** Experimental: checking all function parameter values */ - bool getCheckAllFunctionParameterValues() const { - return mCheckAllFunctionParameterValues; + /** Do not only check how interface is used. Also check that interface is safe. */ + class SafeChecks { + public: + SafeChecks() : classes(false), externalFunctions(false), internalFunctions(false), externalVariables(false) {} + + void clear() { + classes = externalFunctions = internalFunctions = externalVariables = false; + } + + void loadFromXml(QXmlStreamReader &xmlReader); + void saveToXml(QXmlStreamWriter &xmlWriter) const; + + /** + * Public interface of classes + * - public function parameters can have any value + * - public functions can be called in any order + * - public variables can have any value + */ + bool classes; + + /** + * External functions + * - external functions can be called in any order + * - function parameters can have any values + */ + bool externalFunctions; + + /** + * Experimental: assume that internal functions can be used in any way + * This is only available in the GUI. + */ + bool internalFunctions; + + /** + * Global variables that can be modified outside the TU. + * - Such variable can have "any" value + */ + bool externalVariables; + }; + + /** Safe checks */ + SafeChecks getSafeChecks() const { + return mSafeChecks; } - void setCheckAllFunctionParameterValues(bool b) { - mCheckAllFunctionParameterValues = b; + void setSafeChecks(SafeChecks safeChecks) { + mSafeChecks = safeChecks; } /** Check unknown function return values */ @@ -489,7 +529,7 @@ private: /** Max CTU depth */ int mMaxCtuDepth; - bool mCheckAllFunctionParameterValues; + SafeChecks mSafeChecks; QStringList mCheckUnknownFunctionReturn; diff --git a/gui/projectfiledialog.cpp b/gui/projectfiledialog.cpp index ac4b3da13..8db28a6a2 100644 --- a/gui/projectfiledialog.cpp +++ b/gui/projectfiledialog.cpp @@ -283,7 +283,10 @@ void ProjectFileDialog::loadFromProjectFile(const ProjectFile *projectFile) const bool unknownValues = projectFile->getCheckUnknownFunctionReturn().contains(item->text()); item->setCheckState(unknownValues ? Qt::Checked : Qt::Unchecked); // AND initialize check state } - mUI.mAllFunctionsAreSafe->setChecked(projectFile->getCheckAllFunctionParameterValues()); + mUI.mCheckSafeClasses->setChecked(projectFile->getSafeChecks().classes); + mUI.mCheckSafeExternalFunctions->setChecked(projectFile->getSafeChecks().externalFunctions); + mUI.mCheckSafeInternalFunctions->setChecked(projectFile->getSafeChecks().internalFunctions); + mUI.mCheckSafeExternalVariables->setChecked(projectFile->getSafeChecks().externalVariables); // Addons.. QSettings settings; @@ -346,7 +349,12 @@ void ProjectFileDialog::saveToProjectFile(ProjectFile *projectFile) const unknownReturnValues << item->text(); } projectFile->setCheckUnknownFunctionReturn(unknownReturnValues); - projectFile->setCheckAllFunctionParameterValues(mUI.mAllFunctionsAreSafe->isChecked()); + ProjectFile::SafeChecks safeChecks; + safeChecks.classes = mUI.mCheckSafeClasses->isChecked(); + safeChecks.externalFunctions = mUI.mCheckSafeExternalFunctions->isChecked(); + safeChecks.internalFunctions = mUI.mCheckSafeInternalFunctions->isChecked(); + safeChecks.externalVariables = mUI.mCheckSafeExternalVariables->isChecked(); + projectFile->setSafeChecks(safeChecks); // Addons QStringList list; if (mUI.mAddonThreadSafety->isChecked()) diff --git a/gui/projectfiledialog.ui b/gui/projectfiledialog.ui index 050f958ba..cb816d7c2 100644 --- a/gui/projectfiledialog.ui +++ b/gui/projectfiledialog.ui @@ -417,9 +417,105 @@ - Human knowledge + Extended checks + + + + + 0 + 0 + + + + "Safe" interface: Cppcheck does not only check how it is actually used, but analyze any possible usage. + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 200 + + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 840 + 273 + + + + + + + true + + + Classes - Public interface + - public function parameters can have any value + - public functions can be called in any order + - public variables can have any value + + + true + + + + + + + External functions + - External functions can be called in any order + - Function parameters can have any value + + + + + + + External variables + - Variable can have any value + + + + + + + Internal/private functions + - Function parameters can have any value + + + + + + + + + + @@ -468,48 +564,6 @@ - - - - Possible values of function parameters - - - - - - Experimental: All function parameters can have arbitrary values - - - - - - - - - - false - - - All classes must have a "safe" public interface - - - false - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - diff --git a/lib/importproject.cpp b/lib/importproject.cpp index b6348e1e0..28ed09d72 100644 --- a/lib/importproject.cpp +++ b/lib/importproject.cpp @@ -1068,6 +1068,20 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti temp.checkUnusedTemplates = (strcmp(node->GetText(), "true") == 0); else if (strcmp(node->Name(), MaxCtuDepthElementName) == 0) temp.maxCtuDepth = std::atoi(node->GetText()); + else if (strcmp(node->Name(), Settings::SafeChecks::XmlRootName) == 0) { + for (const tinyxml2::XMLElement *child = node->FirstChildElement(); child; child = child->NextSiblingElement()) { + if (strcmp(child->Name(), Settings::SafeChecks::XmlClasses) == 0) + temp.safeChecks.classes = true; + else if (strcmp(child->Name(), Settings::SafeChecks::XmlExternalFunctions) == 0) + temp.safeChecks.externalFunctions = true; + else if (strcmp(child->Name(), Settings::SafeChecks::XmlInternalFunctions) == 0) + temp.safeChecks.internalFunctions = false; // This is not available in CLI + else if (strcmp(child->Name(), Settings::SafeChecks::XmlExternalVariables) == 0) + temp.safeChecks.externalVariables = true; + else + return false; + } + } else return false; } diff --git a/lib/settings.cpp b/lib/settings.cpp index 1e72d9c87..fc75cce78 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -22,6 +22,12 @@ bool Settings::mTerminated; +const char Settings::SafeChecks::XmlRootName[] = "safe-checks"; +const char Settings::SafeChecks::XmlClasses[] = "class-public"; +const char Settings::SafeChecks::XmlExternalFunctions[] = "external-functions"; +const char Settings::SafeChecks::XmlInternalFunctions[] = "internal-functions"; +const char Settings::SafeChecks::XmlExternalVariables[] = "external-variables"; + Settings::Settings() : mEnabled(0), checkConfiguration(false), @@ -39,7 +45,6 @@ Settings::Settings() experimental(false), force(false), inconclusive(false), - allFunctionsAreSafe(false), inlineSuppressions(false), jobs(1), jointSuppressionReport(false), diff --git a/lib/settings.h b/lib/settings.h index c3952dc84..0385e2522 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -146,8 +146,46 @@ public: /** @brief Inconclusive checks */ bool inconclusive; - /** @brief Experimental flag that says all functions are "safe" */ - bool allFunctionsAreSafe; + /** Do not only check how interface is used. Also check that interface is safe. */ + class SafeChecks { + public: + SafeChecks() : classes(false), externalFunctions(false), internalFunctions(false), externalVariables(false) {} + + static const char XmlRootName[]; + static const char XmlClasses[]; + static const char XmlExternalFunctions[]; + static const char XmlInternalFunctions[]; + static const char XmlExternalVariables[]; + + /** + * Public interface of classes + * - public function parameters can have any value + * - public functions can be called in any order + * - public variables can have any value + */ + bool classes; + + /** + * External functions + * - external functions can be called in any order + * - function parameters can have any values + */ + bool externalFunctions; + + /** + * Experimental: assume that internal functions can be used in any way + * This is only available in the GUI. + */ + bool internalFunctions; + + /** + * Global variables that can be modified outside the TU. + * - Such variable can have "any" value + */ + bool externalVariables; + }; + + SafeChecks safeChecks; /** @brief check unknown function return values */ std::set checkUnknownFunctionReturn; diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 570def736..8cf743ef7 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -2081,7 +2081,20 @@ const Token * Function::constructorMemberInitialization() const bool Function::isSafe(const Settings *settings) const { - return settings->allFunctionsAreSafe; + switch (access) { + case AccessControl::Local: + case AccessControl::Private: + case AccessControl::Protected: + return settings->safeChecks.internalFunctions; + case AccessControl::Public: + return settings->safeChecks.classes; + case AccessControl::Namespace: + case AccessControl::Global: + return settings->safeChecks.externalFunctions; + case AccessControl::Throw: + return false; + }; + return false; } Function* SymbolDatabase::addGlobalFunction(Scope*& scope, const Token*& tok, const Token *argStart, const Token* funcStart)