cppcheck/gui/compliancereportdialog.cpp

170 lines
5.6 KiB
C++

#include "compliancereportdialog.h"
#include "ui_compliancereportdialog.h"
#include "filelist.h"
#include "projectfile.h"
#include <QCryptographicHash>
#include <QFile>
#include <QFileDialog>
#include <QFileInfo>
#include <QMessageBox>
#include <QProcess>
#include <QRegularExpression>
#include <QSet>
#include <QTemporaryFile>
#include <QTextStream>
static void addHeaders(const QString& file1, QSet<QString> &allFiles) {
if (allFiles.contains(file1))
return;
QFile file(file1);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
allFiles << file1;
const QRegularExpression re("^#include[ ]*\"([^\">]+)\".*");
QTextStream in(&file);
QString line = in.readLine();
while (!in.atEnd()) {
if (line.startsWith("#include")) {
const QRegularExpressionMatch match = re.match(line);
if (match.hasMatch()) {
QString hfile = match.captured(1);
if (file1.contains("/"))
hfile = file1.mid(0,file1.lastIndexOf("/") + 1) + hfile;
addHeaders(hfile, allFiles);
}
}
line = in.readLine();
}
}
static std::vector<std::string> toStdStringList(const QStringList& from) {
std::vector<std::string> ret;
std::transform(from.cbegin(), from.cend(), std::back_inserter(ret), [](const QString& e) {
return e.toStdString();
});
return ret;
}
ComplianceReportDialog::ComplianceReportDialog(ProjectFile* projectFile, QString resultsFile) :
QDialog(nullptr),
mUI(new Ui::ComplianceReportDialog),
mProjectFile(projectFile),
mResultsFile(std::move(resultsFile))
{
mUI->setupUi(this);
mUI->mEditProjectName->setText(projectFile->getProjectName());
connect(mUI->buttonBox, &QDialogButtonBox::clicked, this, &ComplianceReportDialog::buttonClicked);
}
ComplianceReportDialog::~ComplianceReportDialog()
{
delete mUI;
}
void ComplianceReportDialog::buttonClicked(QAbstractButton* button)
{
switch (mUI->buttonBox->standardButton(button)) {
case QDialogButtonBox::StandardButton::Save:
save();
break;
case QDialogButtonBox::StandardButton::Close:
close();
break;
default:
break;
};
}
void ComplianceReportDialog::save()
{
const QString outFile = QFileDialog::getSaveFileName(this,
tr("Compliance report"),
QDir::homePath() + "/misra-c-2012-compliance-report.html",
tr("HTML files (*.html)"));
if (outFile.isEmpty())
return;
close();
const QString& projectName = mUI->mEditProjectName->text();
const QString& projectVersion = mUI->mEditProjectVersion->text();
const bool files = mUI->mCheckFiles->isChecked();
if (projectName != mProjectFile->getProjectName()) {
mProjectFile->setProjectName(projectName);
mProjectFile->write();
}
QTemporaryFile tempFiles;
if (files && tempFiles.open()) {
QTextStream out(&tempFiles);
FileList fileList;
fileList.addPathList(mProjectFile->getCheckPaths());
if (!mProjectFile->getImportProject().isEmpty()) {
QFileInfo inf(mProjectFile->getFilename());
QString prjfile;
if (QFileInfo(mProjectFile->getImportProject()).isAbsolute())
prjfile = mProjectFile->getImportProject();
else
prjfile = inf.canonicalPath() + '/' + mProjectFile->getImportProject();
ImportProject p;
try {
p.import(prjfile.toStdString());
} catch (InternalError &e) {
QMessageBox msg(QMessageBox::Critical,
tr("Save compliance report"),
tr("Failed to import '%1', can not show files in compliance report").arg(prjfile),
QMessageBox::Ok,
this);
msg.exec();
return;
}
p.ignorePaths(toStdStringList(mProjectFile->getExcludedPaths()));
QDir dir(inf.absoluteDir());
for (const ImportProject::FileSettings& fs: p.fileSettings)
fileList.addFile(dir.relativeFilePath(QString::fromStdString(fs.filename)));
}
QSet<QString> allFiles;
for (const QString &sourcefile: fileList.getFileList())
addHeaders(sourcefile, allFiles);
for (const QString& fileName: allFiles) {
QFile f(fileName);
if (f.open(QFile::ReadOnly)) {
QCryptographicHash hash(QCryptographicHash::Algorithm::Md5);
if (hash.addData(&f)) {
for (auto b: hash.result())
out << QString::number((unsigned char)b,16);
out << " " << fileName << "\n";
}
}
}
tempFiles.close();
}
QStringList args{"--compliant=misra-c2012-1.1",
"--compliant=misra-c2012-1.2",
"--project-name=" + projectName,
"--project-version=" + projectVersion,
"--output-file=" + outFile};
if (files)
args << "--files=" + tempFiles.fileName();
args << mResultsFile;
const QString appPath = QFileInfo(QCoreApplication::applicationFilePath()).canonicalPath();
QProcess process;
#ifdef Q_OS_WIN
process.start(appPath + "/compliance-report.exe", args);
#else
process.start(appPath + "/compliance-report", args);
#endif
process.waitForFinished();
}