GUI: Better history. Prepare for tagging messages.

This commit is contained in:
Daniel Marjamäki 2017-08-02 20:24:23 +02:00
parent 3e2236ac73
commit 78e30e735e
8 changed files with 178 additions and 6 deletions

View File

@ -26,10 +26,16 @@ QErrorPathItem::QErrorPathItem(const ErrorLogger::ErrorMessage::FileLocation &lo
{
}
bool operator==(const QErrorPathItem &i1, const QErrorPathItem &i2)
{
return i1.file == i2.file && i1.col == i2.col && i1.line == i2.line && i1.info == i2.info;
}
ErrorItem::ErrorItem()
: severity(Severity::none)
, inconclusive(false)
, cwe(-1)
, tag(NONE)
{
}
@ -40,6 +46,7 @@ ErrorItem::ErrorItem(const ErrorLogger::ErrorMessage &errmsg)
, summary(QString::fromStdString(errmsg.shortMessage()))
, message(QString::fromStdString(errmsg.verboseMessage()))
, cwe(errmsg._cwe.id)
, tag(NONE)
{
for (std::list<ErrorLogger::ErrorMessage::FileLocation>::const_iterator loc = errmsg._callStack.begin();
loc != errmsg._callStack.end();

View File

@ -59,6 +59,8 @@ public:
QString info;
};
bool operator==(const QErrorPathItem &i1, const QErrorPathItem &i2);
/**
* @brief A class containing error data for one error.
*
@ -86,6 +88,10 @@ public:
QString message;
int cwe;
QList<QErrorPathItem> errorPath;
// Special GUI properties
QString sinceDate;
enum Tag { NONE, FP, IGNORE, BUG } tag;
};
Q_DECLARE_METATYPE(ErrorItem);
@ -103,6 +109,8 @@ public:
Severity::SeverityType severity;
QString summary;
QString message;
QString sinceDate;
ErrorItem::Tag tag;
};
/// @}

View File

@ -872,6 +872,7 @@ void MainWindow::analysisDone()
const QString buildDir = prjpath + '/' + mProjectFile->getBuildDir();
if (QDir(buildDir).exists()) {
mUI.mResults->saveStatistics(buildDir + "/statistics.txt");
mUI.mResults->updateFromOldReport(buildDir + "/lastResults.xml");
mUI.mResults->save(buildDir + "/lastResults.xml", Report::XMLV2);
}
}
@ -1278,6 +1279,13 @@ void MainWindow::stopAnalysis()
{
mThread->stop();
mUI.mResults->disableProgressbar();
if (mProjectFile && !mProjectFile->getBuildDir().isEmpty()) {
const QString prjpath = QFileInfo(mProjectFile->getFilename()).absolutePath();
const QString buildDir = prjpath + '/' + mProjectFile->getBuildDir();
if (QDir(buildDir).exists()) {
mUI.mResults->updateFromOldReport(buildDir + "/lastResults.xml");
}
}
}
void MainWindow::openHelpContents()

View File

@ -47,6 +47,11 @@
#include "showtypes.h"
#include "threadhandler.h"
#include "path.h"
#include "xmlreportv2.h"
// These must match column headers given in ResultsTree::translate()
static const unsigned int COLUMN_SINCE_DATE = 6;
static const unsigned int COLUMN_TAG = 7;
ResultsTree::ResultsTree(QWidget * parent) :
QTreeView(parent),
@ -154,6 +159,8 @@ bool ResultsTree::addErrorItem(const ErrorItem &item)
line.summary = item.summary;
line.message = item.message;
line.severity = item.severity;
line.sinceDate = item.sinceDate;
line.tag = item.tag;
//Create the base item for the error and ensure it has a proper
//file item as a parent
QStandardItem* fileItem = ensureFileItem(item.errorPath.back().file, item.file0, hide);
@ -232,7 +239,22 @@ QStandardItem *ResultsTree::addBacktraceFiles(QStandardItem *parent,
<< createLineNumberItem(QString::number(item.line))
<< createNormalItem(childOfMessage ? QString() : item.errorId)
<< (childOfMessage ? createNormalItem(QString()) : createCheckboxItem(item.inconclusive))
<< createNormalItem(item.summary);
<< createNormalItem(item.summary)
<< createNormalItem(item.sinceDate);
switch (item.tag) {
case ErrorItem::NONE:
list << createNormalItem("");
break;
case ErrorItem::FP:
list << createNormalItem("fp");
break;
case ErrorItem::IGNORE:
list << createNormalItem("ignore");
break;
case ErrorItem::BUG:
list << createNormalItem("bug");
break;
};
//TODO message has parameter names so we'll need changes to the core
//cppcheck so we can get proper translations
@ -1003,12 +1025,86 @@ void ResultsTree::saveErrors(Report *report, QStandardItem *fileItem) const
}
}
QList<ErrorItem> ResultsTree::getAllErrorItems() const
{
QList<ErrorItem> ret;
for (int i = 0; i < mModel.rowCount(); i++) {
const QStandardItem *item = mModel.item(i,0);
for (int j = 0; j < item->rowCount(); j++) {
const QStandardItem *error = item->child(j,0);
ErrorItem errorItem;
readErrorItem(error, &errorItem);
ret << errorItem;
}
}
return ret;
}
static int indexOf(const QList<ErrorItem> &list, const ErrorItem &item)
{
for (int i = 0; i < list.size(); i++) {
if (list[i].errorId == item.errorId &&
list[i].errorPath == item.errorPath &&
list[i].file0 == item.file0 &&
list[i].message == item.message &&
list[i].inconclusive == item.inconclusive &&
list[i].severity == item.severity) {
return i;
}
}
return -1;
}
void ResultsTree::updateFromOldReport(const QString &filename)
{
QList<ErrorItem> oldErrors;
XmlReportV2 oldReport(filename);
if (oldReport.open()) {
oldErrors = oldReport.read();
oldReport.close();
}
// Read current results..
for (int i = 0; i < mModel.rowCount(); i++) {
QStandardItem *fileItem = mModel.item(i,0);
for (int j = 0; j < fileItem->rowCount(); j++) {
QStandardItem *error = fileItem->child(j,0);
ErrorItem errorItem;
readErrorItem(error, &errorItem);
int oldErrorIndex = indexOf(oldErrors, errorItem);
QVariantMap data = error->data().toMap();
// New error .. set the "sinceDate" property
if (oldErrorIndex < 0 || data["sinceDate"].toString().isEmpty()) {
const QString sinceDate = QDate::currentDate().toString(Qt::SystemLocaleShortDate);
data["sinceDate"] = sinceDate;
error->setData(data);
fileItem->child(j, COLUMN_SINCE_DATE)->setText(sinceDate);
if (oldErrorIndex < 0)
continue;
}
if (errorItem.tag != ErrorItem::NONE)
continue;
const ErrorItem &oldErrorItem = oldErrors[oldErrorIndex];
if (oldErrorItem.tag == ErrorItem::FP)
data["tag"] = "fp";
else if (oldErrorItem.tag == ErrorItem::IGNORE)
data["tag"] = "ignore";
else if (oldErrorItem.tag == ErrorItem::BUG)
data["tag"] = "bug";
error->setData(data);
}
}
}
void ResultsTree::readErrorItem(const QStandardItem *error, ErrorItem *item) const
{
//Get error's user data
QVariant userdata = error->data();
//Convert it to QVariantMap
QVariantMap data = userdata.toMap();
// Get error's user data
QVariantMap data = error->data().toMap();
item->severity = ShowTypes::ShowTypeToSeverity(ShowTypes::VariantToShowType(data["severity"]));
item->summary = data["summary"].toString();
@ -1016,6 +1112,14 @@ void ResultsTree::readErrorItem(const QStandardItem *error, ErrorItem *item) con
item->errorId = data["id"].toString();
item->inconclusive = data["inconclusive"].toBool();
item->file0 = data["file0"].toString();
item->sinceDate = data["sinceDate"].toString();
QString tag = data["tag"].toString();
if (tag == "fp")
item->tag = ErrorItem::FP;
else if (tag == "ignore")
item->tag = ErrorItem::IGNORE;
else if (tag == "bug")
item->tag = ErrorItem::BUG;
if (error->rowCount() == 0) {
QErrorPathItem e;
@ -1161,7 +1265,7 @@ bool ResultsTree::hasResults() const
void ResultsTree::translate()
{
QStringList labels;
labels << tr("File") << tr("Severity") << tr("Line") << tr("Id") << tr("Inconclusive") << tr("Summary");
labels << tr("File") << tr("Severity") << tr("Line") << tr("Id") << tr("Inconclusive") << tr("Summary") << tr("Since date") << tr("Tag");
mModel.setHorizontalHeaderLabels(labels);
//TODO go through all the errors in the tree and translate severity and message
}

View File

@ -103,6 +103,16 @@ public:
*/
void saveResults(Report *report) const;
/**
* @brief Get all error items
*/
QList<ErrorItem> getAllErrorItems() const;
/**
* @brief Update items from old report (tag, sinceDate)
*/
void updateFromOldReport(const QString &filename);
/**
* @brief Update tree settings
*

View File

@ -149,6 +149,11 @@ void ResultsView::saveStatistics(const QString &filename) const
ts << "portability:" << mStatistics->getCount(ShowTypes::ShowPortability) << '\n';
}
void ResultsView::updateFromOldReport(const QString &filename) const
{
mUI.mTree->updateFromOldReport(filename);
}
void ResultsView::save(const QString &filename, Report::Type type) const
{
if (!hasResults()) {

View File

@ -88,6 +88,11 @@ public:
*/
void save(const QString &filename, Report::Type type) const;
/**
* @brief Update results from old report (tag, sinceDate)
*/
void updateFromOldReport(const QString &filename) const;
/**
* @brief Update tree settings
*

View File

@ -35,6 +35,8 @@ static const char ErrorsElementName[] = "errors";
static const char LocationElementName[] = "location";
static const char ColAttribute[] = "col";
static const char CWEAttribute[] = "cwe";
static const char SinceDateAttribute[] = "sinceDate";
static const char TagAttribute[] = "tag";
static const char FilenameAttribute[] = "file";
static const char IncludedFromFilenameAttribute[] = "file0";
static const char InconclusiveAttribute[] = "inconclusive";
@ -120,6 +122,14 @@ void XmlReportV2::writeError(const ErrorItem &error)
mXmlWriter->writeAttribute(InconclusiveAttribute, "true");
if (error.cwe > 0)
mXmlWriter->writeAttribute(CWEAttribute, QString::number(error.cwe));
if (!error.sinceDate.isEmpty())
mXmlWriter->writeAttribute(SinceDateAttribute, error.sinceDate);
if (error.tag == ErrorItem::FP)
mXmlWriter->writeAttribute(TagAttribute, "fp");
else if (error.tag == ErrorItem::IGNORE)
mXmlWriter->writeAttribute(TagAttribute, "ignore");
else if (error.tag == ErrorItem::BUG)
mXmlWriter->writeAttribute(TagAttribute, "bug");
for (int i = error.errorPath.count() - 1; i >= 0; i--) {
mXmlWriter->writeStartElement(LocationElementName);
@ -209,6 +219,17 @@ ErrorItem XmlReportV2::readError(QXmlStreamReader *reader)
item.inconclusive = true;
if (attribs.hasAttribute("", CWEAttribute))
item.cwe = attribs.value("", CWEAttribute).toString().toInt();
if (attribs.hasAttribute("", SinceDateAttribute))
item.sinceDate = attribs.value("", SinceDateAttribute).toString();
if (attribs.hasAttribute("", TagAttribute)) {
const QString tag = attribs.value("", TagAttribute).toString();
if (tag == "fp")
item.tag = ErrorItem::FP;
else if (tag == "ignore")
item.tag = ErrorItem::IGNORE;
else if (tag == "bug")
item.tag = ErrorItem::BUG;
}
}
bool errorRead = false;
@ -251,5 +272,9 @@ ErrorItem XmlReportV2::readError(QXmlStreamReader *reader)
break;
}
}
if (item.errorPath.size() == 1 && item.errorPath[0].info.isEmpty())
item.errorPath[0].info = item.message;
return item;
}