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)