Variable contracts
This commit is contained in:
parent
02287d9d34
commit
6277eece67
|
@ -77,7 +77,8 @@ FORMS = about.ui \
|
||||||
librarydialog.ui \
|
librarydialog.ui \
|
||||||
libraryaddfunctiondialog.ui \
|
libraryaddfunctiondialog.ui \
|
||||||
libraryeditargdialog.ui \
|
libraryeditargdialog.ui \
|
||||||
newsuppressiondialog.ui
|
newsuppressiondialog.ui \
|
||||||
|
variablecontractsdialog.ui
|
||||||
|
|
||||||
TRANSLATIONS = cppcheck_de.ts \
|
TRANSLATIONS = cppcheck_de.ts \
|
||||||
cppcheck_es.ts \
|
cppcheck_es.ts \
|
||||||
|
@ -134,6 +135,7 @@ HEADERS += aboutdialog.h \
|
||||||
threadresult.h \
|
threadresult.h \
|
||||||
translationhandler.h \
|
translationhandler.h \
|
||||||
txtreport.h \
|
txtreport.h \
|
||||||
|
variablecontractsdialog.h \
|
||||||
xmlreport.h \
|
xmlreport.h \
|
||||||
xmlreportv2.h \
|
xmlreportv2.h \
|
||||||
librarydialog.h \
|
librarydialog.h \
|
||||||
|
@ -176,6 +178,7 @@ SOURCES += aboutdialog.cpp \
|
||||||
threadresult.cpp \
|
threadresult.cpp \
|
||||||
translationhandler.cpp \
|
translationhandler.cpp \
|
||||||
txtreport.cpp \
|
txtreport.cpp \
|
||||||
|
variablecontractsdialog.cpp \
|
||||||
xmlreport.cpp \
|
xmlreport.cpp \
|
||||||
xmlreportv2.cpp \
|
xmlreportv2.cpp \
|
||||||
librarydialog.cpp \
|
librarydialog.cpp \
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include "threadhandler.h"
|
#include "threadhandler.h"
|
||||||
#include "threadresult.h"
|
#include "threadresult.h"
|
||||||
#include "translationhandler.h"
|
#include "translationhandler.h"
|
||||||
|
#include "variablecontractsdialog.h"
|
||||||
|
|
||||||
static const QString OnlineHelpURL("http://cppcheck.net/manual.html");
|
static const QString OnlineHelpURL("http://cppcheck.net/manual.html");
|
||||||
static const QString compile_commands_json("compile_commands.json");
|
static const QString compile_commands_json("compile_commands.json");
|
||||||
|
@ -144,6 +145,9 @@ MainWindow::MainWindow(TranslationHandler* th, QSettings* settings) :
|
||||||
connect(mUI.mResults, &ResultsView::checkSelected, this, &MainWindow::performSelectedFilesCheck);
|
connect(mUI.mResults, &ResultsView::checkSelected, this, &MainWindow::performSelectedFilesCheck);
|
||||||
connect(mUI.mResults, &ResultsView::suppressIds, this, &MainWindow::suppressIds);
|
connect(mUI.mResults, &ResultsView::suppressIds, this, &MainWindow::suppressIds);
|
||||||
connect(mUI.mResults, &ResultsView::editFunctionContract, this, &MainWindow::editFunctionContract);
|
connect(mUI.mResults, &ResultsView::editFunctionContract, this, &MainWindow::editFunctionContract);
|
||||||
|
connect(mUI.mResults, &ResultsView::editVariableContract, this, &MainWindow::editVariableContract);
|
||||||
|
connect(mUI.mResults, &ResultsView::deleteFunctionContract, this, &MainWindow::deleteFunctionContract);
|
||||||
|
connect(mUI.mResults, &ResultsView::deleteVariableContract, this, &MainWindow::deleteVariableContract);
|
||||||
connect(mUI.mMenuView, &QMenu::aboutToShow, this, &MainWindow::aboutToShowViewMenu);
|
connect(mUI.mMenuView, &QMenu::aboutToShow, this, &MainWindow::aboutToShowViewMenu);
|
||||||
|
|
||||||
// File menu
|
// File menu
|
||||||
|
@ -351,7 +355,8 @@ void MainWindow::loadSettings()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateContractsTab();
|
updateFunctionContractsTab();
|
||||||
|
updateVariableContractsTab();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::saveSettings() const
|
void MainWindow::saveSettings() const
|
||||||
|
@ -611,7 +616,7 @@ QStringList MainWindow::selectFilesToAnalyze(QFileDialog::FileMode mode)
|
||||||
return selected;
|
return selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::updateContractsTab()
|
void MainWindow::updateFunctionContractsTab()
|
||||||
{
|
{
|
||||||
QStringList addedContracts;
|
QStringList addedContracts;
|
||||||
if (mProjectFile) {
|
if (mProjectFile) {
|
||||||
|
@ -619,7 +624,23 @@ void MainWindow::updateContractsTab()
|
||||||
addedContracts << QString::fromStdString(it.first);
|
addedContracts << QString::fromStdString(it.first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mUI.mResults->setAddedContracts(addedContracts);
|
mUI.mResults->setAddedFunctionContracts(addedContracts);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::updateVariableContractsTab()
|
||||||
|
{
|
||||||
|
QStringList added;
|
||||||
|
if (mProjectFile) {
|
||||||
|
for (auto vc: mProjectFile->getVariableContracts()) {
|
||||||
|
QString line = vc.first;
|
||||||
|
if (!vc.second.minValue.empty())
|
||||||
|
line += " min:" + QString::fromStdString(vc.second.minValue);
|
||||||
|
if (!vc.second.maxValue.empty())
|
||||||
|
line += " max:" + QString::fromStdString(vc.second.maxValue);
|
||||||
|
added << line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mUI.mResults->setAddedVariableContracts(added);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::analyzeFiles()
|
void MainWindow::analyzeFiles()
|
||||||
|
@ -865,6 +886,9 @@ Settings MainWindow::getCppcheckSettings()
|
||||||
|
|
||||||
result.functionContracts = mProjectFile->getFunctionContracts();
|
result.functionContracts = mProjectFile->getFunctionContracts();
|
||||||
|
|
||||||
|
for (const auto vc: mProjectFile->getVariableContracts())
|
||||||
|
result.variableContracts[vc.first.toStdString()] = vc.second;
|
||||||
|
|
||||||
const QStringList undefines = mProjectFile->getUndefines();
|
const QStringList undefines = mProjectFile->getUndefines();
|
||||||
foreach (QString undefine, undefines)
|
foreach (QString undefine, undefines)
|
||||||
result.userUndefs.insert(undefine.toStdString());
|
result.userUndefs.insert(undefine.toStdString());
|
||||||
|
@ -1513,7 +1537,9 @@ void MainWindow::loadProjectFile(const QString &filePath)
|
||||||
delete mProjectFile;
|
delete mProjectFile;
|
||||||
mProjectFile = new ProjectFile(filePath, this);
|
mProjectFile = new ProjectFile(filePath, this);
|
||||||
mProjectFile->setActiveProject();
|
mProjectFile->setActiveProject();
|
||||||
updateContractsTab();
|
mUI.mResults->showContracts(mProjectFile->bugHunting);
|
||||||
|
updateFunctionContractsTab();
|
||||||
|
updateVariableContractsTab();
|
||||||
if (!loadLastResults())
|
if (!loadLastResults())
|
||||||
analyzeProject(mProjectFile);
|
analyzeProject(mProjectFile);
|
||||||
}
|
}
|
||||||
|
@ -1639,12 +1665,14 @@ void MainWindow::newProjectFile()
|
||||||
ProjectFileDialog dlg(mProjectFile, this);
|
ProjectFileDialog dlg(mProjectFile, this);
|
||||||
if (dlg.exec() == QDialog::Accepted) {
|
if (dlg.exec() == QDialog::Accepted) {
|
||||||
addProjectMRU(filepath);
|
addProjectMRU(filepath);
|
||||||
|
mUI.mResults->showContracts(mProjectFile->bugHunting);
|
||||||
analyzeProject(mProjectFile);
|
analyzeProject(mProjectFile);
|
||||||
} else {
|
} else {
|
||||||
closeProjectFile();
|
closeProjectFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateContractsTab();
|
updateFunctionContractsTab();
|
||||||
|
updateVariableContractsTab();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::closeProjectFile()
|
void MainWindow::closeProjectFile()
|
||||||
|
@ -1652,6 +1680,8 @@ void MainWindow::closeProjectFile()
|
||||||
delete mProjectFile;
|
delete mProjectFile;
|
||||||
mProjectFile = nullptr;
|
mProjectFile = nullptr;
|
||||||
mUI.mResults->clear(true);
|
mUI.mResults->clear(true);
|
||||||
|
mUI.mResults->clearContracts();
|
||||||
|
mUI.mResults->showContracts(false);
|
||||||
enableProjectActions(false);
|
enableProjectActions(false);
|
||||||
enableProjectOpenActions(true);
|
enableProjectOpenActions(true);
|
||||||
formatAndSetTitle();
|
formatAndSetTitle();
|
||||||
|
@ -1672,6 +1702,7 @@ void MainWindow::editProjectFile()
|
||||||
ProjectFileDialog dlg(mProjectFile, this);
|
ProjectFileDialog dlg(mProjectFile, this);
|
||||||
if (dlg.exec() == QDialog::Accepted) {
|
if (dlg.exec() == QDialog::Accepted) {
|
||||||
mProjectFile->write();
|
mProjectFile->write();
|
||||||
|
mUI.mResults->showContracts(mProjectFile->bugHunting);
|
||||||
analyzeProject(mProjectFile);
|
analyzeProject(mProjectFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1858,5 +1889,35 @@ void MainWindow::editFunctionContract(QString function)
|
||||||
mProjectFile->write();
|
mProjectFile->write();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateContractsTab();
|
updateFunctionContractsTab();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::editVariableContract(QString var)
|
||||||
|
{
|
||||||
|
if (!mProjectFile)
|
||||||
|
return;
|
||||||
|
|
||||||
|
VariableContractsDialog dlg(nullptr, var);
|
||||||
|
if (dlg.exec() == QDialog::Accepted) {
|
||||||
|
mProjectFile->setVariableContracts(dlg.getVarname(), dlg.getMin(), dlg.getMax());
|
||||||
|
mProjectFile->write();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateVariableContractsTab();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::deleteFunctionContract(QString function)
|
||||||
|
{
|
||||||
|
if (mProjectFile) {
|
||||||
|
mProjectFile->deleteFunctionContract(function);
|
||||||
|
mProjectFile->write();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::deleteVariableContract(QString var)
|
||||||
|
{
|
||||||
|
if (mProjectFile) {
|
||||||
|
mProjectFile->deleteVariableContract(var);
|
||||||
|
mProjectFile->write();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,8 +73,11 @@ public:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
/** Update "Contracts" tab */
|
/** Update "Functions" tab */
|
||||||
void updateContractsTab();
|
void updateFunctionContractsTab();
|
||||||
|
|
||||||
|
/** Update "Variables" tab */
|
||||||
|
void updateVariableContractsTab();
|
||||||
|
|
||||||
/** @brief Slot for analyze files menu item */
|
/** @brief Slot for analyze files menu item */
|
||||||
void analyzeFiles();
|
void analyzeFiles();
|
||||||
|
@ -227,6 +230,16 @@ protected slots:
|
||||||
|
|
||||||
/** Edit contract for function */
|
/** Edit contract for function */
|
||||||
void editFunctionContract(QString function);
|
void editFunctionContract(QString function);
|
||||||
|
|
||||||
|
/** Edit constraints for variable */
|
||||||
|
void editVariableContract(QString var);
|
||||||
|
|
||||||
|
/** Delete contract for function */
|
||||||
|
void deleteFunctionContract(QString function);
|
||||||
|
|
||||||
|
/** Edit constraints for variable */
|
||||||
|
void deleteVariableContract(QString var);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/** Get filename for last results */
|
/** Get filename for last results */
|
||||||
|
|
|
@ -59,6 +59,7 @@ void ProjectFile::clear()
|
||||||
mPaths.clear();
|
mPaths.clear();
|
||||||
mExcludedPaths.clear();
|
mExcludedPaths.clear();
|
||||||
mFunctionContracts.clear();
|
mFunctionContracts.clear();
|
||||||
|
mVariableContracts.clear();
|
||||||
mLibraries.clear();
|
mLibraries.clear();
|
||||||
mPlatform.clear();
|
mPlatform.clear();
|
||||||
mSuppressions.clear();
|
mSuppressions.clear();
|
||||||
|
@ -156,6 +157,10 @@ bool ProjectFile::read(const QString &filename)
|
||||||
if (xmlReader.name() == CppcheckXml::FunctionContracts)
|
if (xmlReader.name() == CppcheckXml::FunctionContracts)
|
||||||
readFunctionContracts(xmlReader);
|
readFunctionContracts(xmlReader);
|
||||||
|
|
||||||
|
// Variable constraints
|
||||||
|
if (xmlReader.name() == CppcheckXml::VariableContractsElementName)
|
||||||
|
readVariableContracts(xmlReader);
|
||||||
|
|
||||||
// Find libraries list from inside project element
|
// Find libraries list from inside project element
|
||||||
if (xmlReader.name() == CppcheckXml::LibrariesElementName)
|
if (xmlReader.name() == CppcheckXml::LibrariesElementName)
|
||||||
readStringList(mLibraries, xmlReader, CppcheckXml::LibraryElementName);
|
readStringList(mLibraries, xmlReader, CppcheckXml::LibraryElementName);
|
||||||
|
@ -531,6 +536,42 @@ void ProjectFile::readFunctionContracts(QXmlStreamReader &reader)
|
||||||
} while (!allRead);
|
} while (!allRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProjectFile::readVariableContracts(QXmlStreamReader &reader)
|
||||||
|
{
|
||||||
|
QXmlStreamReader::TokenType type;
|
||||||
|
while (true) {
|
||||||
|
type = reader.readNext();
|
||||||
|
switch (type) {
|
||||||
|
case QXmlStreamReader::StartElement:
|
||||||
|
if (reader.name().toString() == CppcheckXml::VariableContractItemElementName) {
|
||||||
|
QXmlStreamAttributes attribs = reader.attributes();
|
||||||
|
QString varname = attribs.value(QString(), CppcheckXml::VariableContractVarName).toString();
|
||||||
|
QString minValue = attribs.value(QString(), CppcheckXml::VariableContractMin).toString();
|
||||||
|
QString maxValue = attribs.value(QString(), CppcheckXml::VariableContractMax).toString();
|
||||||
|
setVariableContracts(varname, minValue, maxValue);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QXmlStreamReader::EndElement:
|
||||||
|
if (reader.name().toString() == CppcheckXml::VariableContractsElementName)
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Not handled
|
||||||
|
case QXmlStreamReader::NoToken:
|
||||||
|
case QXmlStreamReader::Invalid:
|
||||||
|
case QXmlStreamReader::StartDocument:
|
||||||
|
case QXmlStreamReader::EndDocument:
|
||||||
|
case QXmlStreamReader::Characters:
|
||||||
|
case QXmlStreamReader::Comment:
|
||||||
|
case QXmlStreamReader::DTD:
|
||||||
|
case QXmlStreamReader::EntityReference:
|
||||||
|
case QXmlStreamReader::ProcessingInstruction:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ProjectFile::readVsConfigurations(QXmlStreamReader &reader)
|
void ProjectFile::readVsConfigurations(QXmlStreamReader &reader)
|
||||||
{
|
{
|
||||||
QXmlStreamReader::TokenType type;
|
QXmlStreamReader::TokenType type;
|
||||||
|
@ -926,6 +967,20 @@ bool ProjectFile::write(const QString &filename)
|
||||||
xmlWriter.writeEndElement();
|
xmlWriter.writeEndElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!mVariableContracts.empty()) {
|
||||||
|
xmlWriter.writeStartElement(CppcheckXml::VariableContractsElementName);
|
||||||
|
|
||||||
|
for (auto vc: mVariableContracts) {
|
||||||
|
xmlWriter.writeStartElement(CppcheckXml::VariableContractItemElementName);
|
||||||
|
xmlWriter.writeAttribute(CppcheckXml::VariableContractVarName, vc.first);
|
||||||
|
xmlWriter.writeAttribute(CppcheckXml::VariableContractMin, QString::fromStdString(vc.second.minValue));
|
||||||
|
xmlWriter.writeAttribute(CppcheckXml::VariableContractMax, QString::fromStdString(vc.second.maxValue));
|
||||||
|
xmlWriter.writeEndElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlWriter.writeEndElement();
|
||||||
|
}
|
||||||
|
|
||||||
if (!mSuppressions.isEmpty()) {
|
if (!mSuppressions.isEmpty()) {
|
||||||
xmlWriter.writeStartElement(CppcheckXml::SuppressionsElementName);
|
xmlWriter.writeStartElement(CppcheckXml::SuppressionsElementName);
|
||||||
foreach (const Suppressions::Suppression &suppression, mSuppressions) {
|
foreach (const Suppressions::Suppression &suppression, mSuppressions) {
|
||||||
|
|
|
@ -230,6 +230,24 @@ public:
|
||||||
return mFunctionContracts;
|
return mFunctionContracts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::map<QString, Settings::VariableContracts>& getVariableContracts() const {
|
||||||
|
return mVariableContracts;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setVariableContracts(QString var, QString min, QString max) {
|
||||||
|
mVariableContracts[var] = Settings::VariableContracts{min.toStdString(), max.toStdString()};
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteFunctionContract(QString function)
|
||||||
|
{
|
||||||
|
mFunctionContracts.erase(function.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteVariableContract(QString var)
|
||||||
|
{
|
||||||
|
mVariableContracts.erase(var);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get filename for the project file.
|
* @brief Get filename for the project file.
|
||||||
* @return file name.
|
* @return file name.
|
||||||
|
@ -425,6 +443,12 @@ protected:
|
||||||
*/
|
*/
|
||||||
void readFunctionContracts(QXmlStreamReader &reader);
|
void readFunctionContracts(QXmlStreamReader &reader);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read variable constraints.
|
||||||
|
* @param reader XML stream reader.
|
||||||
|
*/
|
||||||
|
void readVariableContracts(QXmlStreamReader &reader);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read lists of Visual Studio configurations
|
* @brief Read lists of Visual Studio configurations
|
||||||
* @param reader XML stream reader.
|
* @param reader XML stream reader.
|
||||||
|
@ -542,6 +566,8 @@ private:
|
||||||
|
|
||||||
std::map<std::string, std::string> mFunctionContracts;
|
std::map<std::string, std::string> mFunctionContracts;
|
||||||
|
|
||||||
|
std::map<QString, Settings::VariableContracts> mVariableContracts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Platform
|
* @brief Platform
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -61,8 +61,17 @@ ResultsView::ResultsView(QWidget * parent) :
|
||||||
connect(this, &ResultsView::collapseAllResults, mUI.mTree, &ResultsTree::collapseAll);
|
connect(this, &ResultsView::collapseAllResults, mUI.mTree, &ResultsTree::collapseAll);
|
||||||
connect(this, &ResultsView::expandAllResults, mUI.mTree, &ResultsTree::expandAll);
|
connect(this, &ResultsView::expandAllResults, mUI.mTree, &ResultsTree::expandAll);
|
||||||
connect(this, &ResultsView::showHiddenResults, mUI.mTree, &ResultsTree::showHiddenResults);
|
connect(this, &ResultsView::showHiddenResults, mUI.mTree, &ResultsTree::showHiddenResults);
|
||||||
|
|
||||||
|
// Function contracts
|
||||||
connect(mUI.mListAddedContracts, &QListWidget::itemDoubleClicked, this, &ResultsView::contractDoubleClicked);
|
connect(mUI.mListAddedContracts, &QListWidget::itemDoubleClicked, this, &ResultsView::contractDoubleClicked);
|
||||||
connect(mUI.mListMissingContracts, &QListWidget::itemDoubleClicked, this, &ResultsView::contractDoubleClicked);
|
connect(mUI.mListMissingContracts, &QListWidget::itemDoubleClicked, this, &ResultsView::contractDoubleClicked);
|
||||||
|
mUI.mListAddedContracts->installEventFilter(this);
|
||||||
|
|
||||||
|
// Variable contracts
|
||||||
|
connect(mUI.mListAddedVariables, &QListWidget::itemDoubleClicked, this, &ResultsView::variableDoubleClicked);
|
||||||
|
connect(mUI.mListMissingVariables, &QListWidget::itemDoubleClicked, this, &ResultsView::variableDoubleClicked);
|
||||||
|
connect(mUI.mEditVariablesFilter, &QLineEdit::textChanged, this, &ResultsView::editVariablesFilter);
|
||||||
|
mUI.mListAddedVariables->installEventFilter(this);
|
||||||
|
|
||||||
mUI.mListLog->setContextMenuPolicy(Qt::CustomContextMenu);
|
mUI.mListLog->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
|
||||||
|
@ -90,7 +99,7 @@ ResultsView::~ResultsView()
|
||||||
//dtor
|
//dtor
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResultsView::setAddedContracts(const QStringList &addedContracts)
|
void ResultsView::setAddedFunctionContracts(const QStringList &addedContracts)
|
||||||
{
|
{
|
||||||
mUI.mListAddedContracts->clear();
|
mUI.mListAddedContracts->clear();
|
||||||
mUI.mListAddedContracts->addItems(addedContracts);
|
mUI.mListAddedContracts->addItems(addedContracts);
|
||||||
|
@ -101,6 +110,17 @@ void ResultsView::setAddedContracts(const QStringList &addedContracts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ResultsView::setAddedVariableContracts(const QStringList &added)
|
||||||
|
{
|
||||||
|
mUI.mListAddedVariables->clear();
|
||||||
|
mUI.mListAddedVariables->addItems(added);
|
||||||
|
for (const QString var: added) {
|
||||||
|
for (auto item: mUI.mListMissingVariables->findItems(var, Qt::MatchExactly))
|
||||||
|
delete item;
|
||||||
|
mVariableContracts.insert(var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ResultsView::clear(bool results)
|
void ResultsView::clear(bool results)
|
||||||
{
|
{
|
||||||
if (results) {
|
if (results) {
|
||||||
|
@ -127,6 +147,22 @@ void ResultsView::clearRecheckFile(const QString &filename)
|
||||||
mUI.mTree->clearRecheckFile(filename);
|
mUI.mTree->clearRecheckFile(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ResultsView::clearContracts()
|
||||||
|
{
|
||||||
|
mUI.mListAddedContracts->clear();
|
||||||
|
mUI.mListAddedVariables->clear();
|
||||||
|
mUI.mListMissingContracts->clear();
|
||||||
|
mUI.mListMissingVariables->clear();
|
||||||
|
mFunctionContracts.clear();
|
||||||
|
mVariableContracts.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResultsView::showContracts(bool visible)
|
||||||
|
{
|
||||||
|
mUI.mTabFunctionContracts->setVisible(visible);
|
||||||
|
mUI.mTabVariableContracts->setVisible(visible);
|
||||||
|
}
|
||||||
|
|
||||||
void ResultsView::progress(int value, const QString& description)
|
void ResultsView::progress(int value, const QString& description)
|
||||||
{
|
{
|
||||||
mUI.mProgress->setValue(value);
|
mUI.mProgress->setValue(value);
|
||||||
|
@ -458,12 +494,16 @@ void ResultsView::debugError(const ErrorItem &item)
|
||||||
void ResultsView::bughuntingReportLine(const QString& line)
|
void ResultsView::bughuntingReportLine(const QString& line)
|
||||||
{
|
{
|
||||||
for (const QString& s: line.split("\n")) {
|
for (const QString& s: line.split("\n")) {
|
||||||
if (s.isEmpty())
|
if (s.startsWith("[intvar] ")) {
|
||||||
continue;
|
const QString varname = s.mid(9);
|
||||||
if (s.startsWith("[missing contract] ")) {
|
if (!mVariableContracts.contains(varname)) {
|
||||||
|
mVariableContracts.insert(varname);
|
||||||
|
mUI.mListMissingVariables->addItem(varname);
|
||||||
|
}
|
||||||
|
} else if (s.startsWith("[missing contract] ")) {
|
||||||
const QString functionName = s.mid(19);
|
const QString functionName = s.mid(19);
|
||||||
if (!mContracts.contains(functionName)) {
|
if (!mFunctionContracts.contains(functionName)) {
|
||||||
mContracts.insert(functionName);
|
mFunctionContracts.insert(functionName);
|
||||||
mUI.mListMissingContracts->addItem(functionName);
|
mUI.mListMissingContracts->addItem(functionName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -502,6 +542,21 @@ void ResultsView::contractDoubleClicked(QListWidgetItem* item)
|
||||||
emit editFunctionContract(item->text());
|
emit editFunctionContract(item->text());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ResultsView::variableDoubleClicked(QListWidgetItem* item)
|
||||||
|
{
|
||||||
|
emit editVariableContract(item->text());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResultsView::editVariablesFilter(const QString &text)
|
||||||
|
{
|
||||||
|
for (auto item: mUI.mListAddedVariables->findItems(".*", Qt::MatchRegExp)) {
|
||||||
|
QString varname = item->text().mid(0, item->text().indexOf(" "));
|
||||||
|
item->setHidden(!varname.contains(text));
|
||||||
|
}
|
||||||
|
for (auto item: mUI.mListMissingVariables->findItems(".*", Qt::MatchRegExp))
|
||||||
|
item->setHidden(!item->text().contains(text));
|
||||||
|
}
|
||||||
|
|
||||||
void ResultsView::on_mListLog_customContextMenuRequested(const QPoint &pos)
|
void ResultsView::on_mListLog_customContextMenuRequested(const QPoint &pos)
|
||||||
{
|
{
|
||||||
if (mUI.mListLog->count() <= 0)
|
if (mUI.mListLog->count() <= 0)
|
||||||
|
@ -516,3 +571,32 @@ void ResultsView::on_mListLog_customContextMenuRequested(const QPoint &pos)
|
||||||
|
|
||||||
contextMenu.exec(globalPos);
|
contextMenu.exec(globalPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ResultsView::eventFilter(QObject *target, QEvent *event)
|
||||||
|
{
|
||||||
|
if (event->type() == QEvent::KeyPress) {
|
||||||
|
if (target == mUI.mListAddedVariables) {
|
||||||
|
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||||
|
if (keyEvent->key() == Qt::Key_Delete) {
|
||||||
|
for (auto i: mUI.mListAddedVariables->selectedItems()) {
|
||||||
|
emit deleteVariableContract(i->text().mid(0, i->text().indexOf(" ")));
|
||||||
|
delete i;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target == mUI.mListAddedContracts) {
|
||||||
|
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||||
|
if (keyEvent->key() == Qt::Key_Delete) {
|
||||||
|
for (auto i: mUI.mListAddedContracts->selectedItems()) {
|
||||||
|
emit deleteFunctionContract(i->text());
|
||||||
|
delete i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QObject::eventFilter(target, event);
|
||||||
|
}
|
||||||
|
|
|
@ -50,7 +50,8 @@ public:
|
||||||
virtual ~ResultsView();
|
virtual ~ResultsView();
|
||||||
ResultsView &operator=(const ResultsView &) = delete;
|
ResultsView &operator=(const ResultsView &) = delete;
|
||||||
|
|
||||||
void setAddedContracts(const QStringList &addedContracts);
|
void setAddedFunctionContracts(const QStringList &addedContracts);
|
||||||
|
void setAddedVariableContracts(const QStringList &added);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Clear results and statistics and reset progressinfo.
|
* @brief Clear results and statistics and reset progressinfo.
|
||||||
|
@ -68,6 +69,9 @@ public:
|
||||||
*/
|
*/
|
||||||
void clearRecheckFile(const QString &filename);
|
void clearRecheckFile(const QString &filename);
|
||||||
|
|
||||||
|
/** Clear the contracts */
|
||||||
|
void clearContracts();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Write statistics in file
|
* @brief Write statistics in file
|
||||||
*
|
*
|
||||||
|
@ -196,6 +200,9 @@ public:
|
||||||
return &mUI.mTree->mShowSeverities;
|
return &mUI.mTree->mShowSeverities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Show/hide the contract tabs */
|
||||||
|
void showContracts(bool visible);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -224,6 +231,15 @@ signals:
|
||||||
/** Edit contract for function */
|
/** Edit contract for function */
|
||||||
void editFunctionContract(QString function);
|
void editFunctionContract(QString function);
|
||||||
|
|
||||||
|
/** Delete contract for function */
|
||||||
|
void deleteFunctionContract(QString function);
|
||||||
|
|
||||||
|
/** Edit contract for variable */
|
||||||
|
void editVariableContract(QString var);
|
||||||
|
|
||||||
|
/** Delete variable contract */
|
||||||
|
void deleteVariableContract(QString var);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Show/hide certain type of errors
|
* @brief Show/hide certain type of errors
|
||||||
* Refreshes the tree.
|
* Refreshes the tree.
|
||||||
|
@ -342,6 +358,11 @@ public slots:
|
||||||
/** \brief Contract was double clicked => edit it */
|
/** \brief Contract was double clicked => edit it */
|
||||||
void contractDoubleClicked(QListWidgetItem* item);
|
void contractDoubleClicked(QListWidgetItem* item);
|
||||||
|
|
||||||
|
/** \brief Variable was double clicked => edit it */
|
||||||
|
void variableDoubleClicked(QListWidgetItem* item);
|
||||||
|
|
||||||
|
void editVariablesFilter(const QString &text);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief Should we show a "No errors found dialog" every time no errors were found?
|
* @brief Should we show a "No errors found dialog" every time no errors were found?
|
||||||
|
@ -351,6 +372,8 @@ protected:
|
||||||
Ui::ResultsView mUI;
|
Ui::ResultsView mUI;
|
||||||
|
|
||||||
CheckStatistics *mStatistics;
|
CheckStatistics *mStatistics;
|
||||||
|
|
||||||
|
bool eventFilter(QObject *target, QEvent *event);
|
||||||
private slots:
|
private slots:
|
||||||
/**
|
/**
|
||||||
* @brief Custom context menu for Analysis Log
|
* @brief Custom context menu for Analysis Log
|
||||||
|
@ -358,7 +381,8 @@ private slots:
|
||||||
*/
|
*/
|
||||||
void on_mListLog_customContextMenuRequested(const QPoint &pos);
|
void on_mListLog_customContextMenuRequested(const QPoint &pos);
|
||||||
private:
|
private:
|
||||||
QSet<QString> mContracts;
|
QSet<QString> mFunctionContracts;
|
||||||
|
QSet<QString> mVariableContracts;
|
||||||
|
|
||||||
/** Current file shown in the code editor */
|
/** Current file shown in the code editor */
|
||||||
QString mCurrentFileName;
|
QString mCurrentFileName;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>459</width>
|
<width>459</width>
|
||||||
<height>358</height>
|
<height>391</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
|
@ -153,9 +153,9 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="mTabContracts">
|
<widget class="QWidget" name="mTabFunctionContracts">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>Contracts</string>
|
<string>Functions</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||||
<item>
|
<item>
|
||||||
|
@ -191,6 +191,71 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QWidget" name="mTabVariableContracts">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Variables</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Only show variable names that contain text:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="mEditVariablesFilter"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Configured contracts:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="mListAddedVariables">
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Missing contracts:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="mListMissingVariables">
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="sortingEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
#include "variablecontractsdialog.h"
|
||||||
|
#include "ui_variablecontractsdialog.h"
|
||||||
|
|
||||||
|
#include <QRegExpValidator>
|
||||||
|
|
||||||
|
VariableContractsDialog::VariableContractsDialog(QWidget *parent, QString var) :
|
||||||
|
QDialog(parent),
|
||||||
|
ui(new Ui::VariableContractsDialog)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
mVarName = var.indexOf(" ") < 0 ? var : var.mid(0, var.indexOf(" "));
|
||||||
|
|
||||||
|
this->setWindowTitle(mVarName);
|
||||||
|
|
||||||
|
auto getMinMax = [](QString var, QString minmax) {
|
||||||
|
if (var.indexOf(" " + minmax + ":") < 0)
|
||||||
|
return QString();
|
||||||
|
int pos1 = var.indexOf(" " + minmax + ":") + 2 + minmax.length();
|
||||||
|
int pos2 = var.indexOf(" ", pos1);
|
||||||
|
if (pos2 < 0)
|
||||||
|
return var.mid(pos1);
|
||||||
|
return var.mid(pos1, pos2-pos1);
|
||||||
|
};
|
||||||
|
|
||||||
|
ui->mMinValue->setText(getMinMax(var, "min"));
|
||||||
|
ui->mMaxValue->setText(getMinMax(var, "max"));
|
||||||
|
|
||||||
|
ui->mMinValue->setValidator(new QRegExpValidator(QRegExp("-?[0-9]*")));
|
||||||
|
ui->mMaxValue->setValidator(new QRegExpValidator(QRegExp("-?[0-9]*")));
|
||||||
|
}
|
||||||
|
|
||||||
|
VariableContractsDialog::~VariableContractsDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString VariableContractsDialog::getVarname() const
|
||||||
|
{
|
||||||
|
return mVarName;
|
||||||
|
}
|
||||||
|
QString VariableContractsDialog::getMin() const
|
||||||
|
{
|
||||||
|
return ui->mMinValue->text();
|
||||||
|
}
|
||||||
|
QString VariableContractsDialog::getMax() const
|
||||||
|
{
|
||||||
|
return ui->mMaxValue->text();
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef VARIABLECONSTRAINTSDIALOG_H
|
||||||
|
#define VARIABLECONSTRAINTSDIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class VariableContractsDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class VariableContractsDialog : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit VariableContractsDialog(QWidget *parent, QString var);
|
||||||
|
~VariableContractsDialog();
|
||||||
|
|
||||||
|
QString getVarname() const;
|
||||||
|
QString getMin() const;
|
||||||
|
QString getMax() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::VariableContractsDialog *ui;
|
||||||
|
QString mVarName;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VARIABLECONSTRAINTSDIALOG_H
|
|
@ -0,0 +1,108 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>VariableContractsDialog</class>
|
||||||
|
<widget class="QDialog" name="VariableContractsDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>172</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>You can specify min and max value for the variable here</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Min</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="mMinValue"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Max</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="mMaxValue"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>25</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>VariableContractsDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>VariableContractsDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
|
@ -505,14 +505,44 @@ static void checkAssignment(const Token *tok, const ExprEngine::Value &value, Ex
|
||||||
|
|
||||||
const Token *vartok = lhs->variable()->nameToken();
|
const Token *vartok = lhs->variable()->nameToken();
|
||||||
|
|
||||||
|
bool executable = false;
|
||||||
|
std::string fullName = lhs->variable()->name();
|
||||||
|
for (const Scope *s = lhs->variable()->nameToken()->scope(); s->type != Scope::ScopeType::eGlobal; s = s->nestedIn) {
|
||||||
|
if (s->isExecutable()) {
|
||||||
|
executable = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fullName = s->className + "::" + fullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto getMinMaxValue = [=](TokenImpl::CppcheckAttributes::Type type, MathLib::bigint *val) {
|
||||||
|
if (vartok->getCppcheckAttribute(type, val))
|
||||||
|
return true;
|
||||||
|
if (!executable) {
|
||||||
|
const auto it = dataBase->settings->variableContracts.find(fullName);
|
||||||
|
if (it != dataBase->settings->variableContracts.end()) {
|
||||||
|
const std::string *str;
|
||||||
|
if (type == TokenImpl::CppcheckAttributes::Type::LOW)
|
||||||
|
str = &it->second.minValue;
|
||||||
|
else if (type == TokenImpl::CppcheckAttributes::Type::HIGH)
|
||||||
|
str = &it->second.maxValue;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
*val = MathLib::toLongNumber(*str);
|
||||||
|
return !str->empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
MathLib::bigint low;
|
MathLib::bigint low;
|
||||||
if (vartok->getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, &low)) {
|
if (getMinMaxValue(TokenImpl::CppcheckAttributes::Type::LOW, &low)) {
|
||||||
if (value.isLessThan(dataBase, low))
|
if (value.isLessThan(dataBase, low))
|
||||||
dataBase->reportError(tok, Severity::SeverityType::error, "bughuntingAssign", "There is assignment, cannot determine that value is greater or equal with " + std::to_string(low), CWE_INCORRECT_CALCULATION, false);
|
dataBase->reportError(tok, Severity::SeverityType::error, "bughuntingAssign", "There is assignment, cannot determine that value is greater or equal with " + std::to_string(low), CWE_INCORRECT_CALCULATION, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
MathLib::bigint high;
|
MathLib::bigint high;
|
||||||
if (vartok->getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, &high)) {
|
if (getMinMaxValue(TokenImpl::CppcheckAttributes::Type::HIGH, &high)) {
|
||||||
if (value.isGreaterThan(dataBase, high))
|
if (value.isGreaterThan(dataBase, high))
|
||||||
dataBase->reportError(tok, Severity::SeverityType::error, "bughuntingAssign", "There is assignment, cannot determine that value is lower or equal with " + std::to_string(high), CWE_INCORRECT_CALCULATION, false);
|
dataBase->reportError(tok, Severity::SeverityType::error, "bughuntingAssign", "There is assignment, cannot determine that value is lower or equal with " + std::to_string(high), CWE_INCORRECT_CALCULATION, false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2641,6 +2641,28 @@ void ExprEngine::executeFunction(const Scope *functionScope, ErrorLogger *errorL
|
||||||
|
|
||||||
// Write a report
|
// Write a report
|
||||||
if (bugHuntingReport) {
|
if (bugHuntingReport) {
|
||||||
|
std::set<std::string> intvars;
|
||||||
|
for (const Scope &scope: tokenizer->getSymbolDatabase()->scopeList) {
|
||||||
|
if (scope.isExecutable())
|
||||||
|
continue;
|
||||||
|
std::string path;
|
||||||
|
bool valid = true;
|
||||||
|
for (const Scope *s = &scope; s->type != Scope::ScopeType::eGlobal; s = s->nestedIn) {
|
||||||
|
if (s->isExecutable()) {
|
||||||
|
valid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
path = s->className + "::" + path;
|
||||||
|
}
|
||||||
|
if (!valid)
|
||||||
|
continue;
|
||||||
|
for (const Variable &var: scope.varlist) {
|
||||||
|
if (var.nameToken() && !var.nameToken()->hasCppcheckAttributes() && var.valueType() && var.valueType()->pointer == 0 && var.valueType()->constness == 0 && var.valueType()->isIntegral())
|
||||||
|
intvars.insert(path + var.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const std::string &v: intvars)
|
||||||
|
report << "[intvar] " << v << std::endl;
|
||||||
for (const std::string &f: trackExecution.getMissingContracts())
|
for (const std::string &f: trackExecution.getMissingContracts())
|
||||||
report << "[missing contract] " << f << std::endl;
|
report << "[missing contract] " << f << std::endl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1068,6 +1068,16 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti
|
||||||
temp.functionContracts[function] = expects;
|
temp.functionContracts[function] = expects;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (strcmp(node->Name(), CppcheckXml::VariableContractsElementName) == 0) {
|
||||||
|
for (const tinyxml2::XMLElement *child = node->FirstChildElement(); child; child = child->NextSiblingElement()) {
|
||||||
|
if (strcmp(child->Name(), CppcheckXml::VariableContractItemElementName) == 0) {
|
||||||
|
const char *name = child->Attribute(CppcheckXml::VariableContractVarName);
|
||||||
|
const char *min = child->Attribute(CppcheckXml::VariableContractMin);
|
||||||
|
const char *max = child->Attribute(CppcheckXml::VariableContractMax);
|
||||||
|
if (name)
|
||||||
|
temp.variableContracts[name] = Settings::VariableContracts{min?min:"", max?max:""};
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (strcmp(node->Name(), CppcheckXml::IgnoreElementName) == 0)
|
} else if (strcmp(node->Name(), CppcheckXml::IgnoreElementName) == 0)
|
||||||
guiProject.excludedPaths = readXmlStringList(node, "", CppcheckXml::IgnorePathName, CppcheckXml::IgnorePathNameAttrib);
|
guiProject.excludedPaths = readXmlStringList(node, "", CppcheckXml::IgnorePathName, CppcheckXml::IgnorePathNameAttrib);
|
||||||
else if (strcmp(node->Name(), CppcheckXml::LibrariesElementName) == 0)
|
else if (strcmp(node->Name(), CppcheckXml::LibrariesElementName) == 0)
|
||||||
|
|
|
@ -150,6 +150,11 @@ namespace CppcheckXml {
|
||||||
const char FunctionContract[] = "contract";
|
const char FunctionContract[] = "contract";
|
||||||
const char ContractFunction[] = "function";
|
const char ContractFunction[] = "function";
|
||||||
const char ContractExpects[] = "expects";
|
const char ContractExpects[] = "expects";
|
||||||
|
const char VariableContractsElementName[] = "variable-contracts";
|
||||||
|
const char VariableContractItemElementName[] = "var";
|
||||||
|
const char VariableContractVarName[] = "name";
|
||||||
|
const char VariableContractMin[] = "min";
|
||||||
|
const char VariableContractMax[] = "max";
|
||||||
const char LibrariesElementName[] = "libraries";
|
const char LibrariesElementName[] = "libraries";
|
||||||
const char LibraryElementName[] = "library";
|
const char LibraryElementName[] = "library";
|
||||||
const char PlatformElementName[] = "platform";
|
const char PlatformElementName[] = "platform";
|
||||||
|
|
|
@ -176,6 +176,12 @@ public:
|
||||||
|
|
||||||
std::map<std::string, std::string> functionContracts;
|
std::map<std::string, std::string> functionContracts;
|
||||||
|
|
||||||
|
struct VariableContracts {
|
||||||
|
std::string minValue;
|
||||||
|
std::string maxValue;
|
||||||
|
};
|
||||||
|
std::map<std::string, VariableContracts> variableContracts;
|
||||||
|
|
||||||
/** @brief List of include paths, e.g. "my/includes/" which should be used
|
/** @brief List of include paths, e.g. "my/includes/" which should be used
|
||||||
for finding include files inside source files. (-I) */
|
for finding include files inside source files. (-I) */
|
||||||
std::list<std::string> includePaths;
|
std::list<std::string> includePaths;
|
||||||
|
|
|
@ -561,6 +561,9 @@ public:
|
||||||
bool getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint *value) const {
|
bool getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint *value) const {
|
||||||
return mImpl->getCppcheckAttribute(type, value);
|
return mImpl->getCppcheckAttribute(type, value);
|
||||||
}
|
}
|
||||||
|
bool hasCppcheckAttributes() const {
|
||||||
|
return nullptr != mImpl->mCppcheckAttributes;
|
||||||
|
}
|
||||||
bool isControlFlowKeyword() const {
|
bool isControlFlowKeyword() const {
|
||||||
return getFlag(fIsControlFlowKeyword);
|
return getFlag(fIsControlFlowKeyword);
|
||||||
}
|
}
|
||||||
|
|
|
@ -927,7 +927,7 @@ Cppcheck will warn:
|
||||||
|
|
||||||
There are two ways:
|
There are two ways:
|
||||||
|
|
||||||
- Open the "Contracts" tab at the bottom of the screen. Find the function in the listbox and double click on it.
|
- Open the "Functions" or "Variables" tab at the bottom of the screen. Find the function or variable in the listbox and double click on it.
|
||||||
- Right click on a warning and click on "Edit contract.." in the popup menu. This popup menu item is only available if the warning is not inconclusive.
|
- Right click on a warning and click on "Edit contract.." in the popup menu. This popup menu item is only available if the warning is not inconclusive.
|
||||||
|
|
||||||
## Incomplete analysis
|
## Incomplete analysis
|
||||||
|
|
|
@ -35,6 +35,7 @@ private:
|
||||||
#ifdef USE_Z3
|
#ifdef USE_Z3
|
||||||
settings.inconclusive = true;
|
settings.inconclusive = true;
|
||||||
LOAD_LIB_2(settings.library, "std.cfg");
|
LOAD_LIB_2(settings.library, "std.cfg");
|
||||||
|
TEST_CASE(checkAssignment);
|
||||||
TEST_CASE(uninit);
|
TEST_CASE(uninit);
|
||||||
TEST_CASE(uninit_array);
|
TEST_CASE(uninit_array);
|
||||||
TEST_CASE(uninit_function_par);
|
TEST_CASE(uninit_function_par);
|
||||||
|
@ -53,6 +54,15 @@ private:
|
||||||
ExprEngine::runChecks(this, &tokenizer, &settings);
|
ExprEngine::runChecks(this, &tokenizer, &settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void checkAssignment() {
|
||||||
|
check("void foo(int any) { __cppcheck_low__(0) int x; x = any; }");
|
||||||
|
ASSERT_EQUALS("[test.cpp:1]: (error) There is assignment, cannot determine that value is greater or equal with 0\n", errout.str());
|
||||||
|
|
||||||
|
check("struct S { __cppcheck_low__(0) int x; };\n"
|
||||||
|
"void foo(S *s, int any) { s->x = any; }");
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (error) There is assignment, cannot determine that value is greater or equal with 0\n", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void uninit() {
|
void uninit() {
|
||||||
check("void foo() { int x; x = x + 1; }");
|
check("void foo() { int x; x = x + 1; }");
|
||||||
ASSERT_EQUALS("[test.cpp:1]: (error) Cannot determine that 'x' is initialized\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:1]: (error) Cannot determine that 'x' is initialized\n", errout.str());
|
||||||
|
|
Loading…
Reference in New Issue