Fixed #2363 (GUI: Using addons in the checking)
This commit is contained in:
parent
3c7f6cf9c8
commit
dfc48be70e
|
@ -18,6 +18,9 @@
|
|||
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
#include "checkthread.h"
|
||||
#include "threadresult.h"
|
||||
#include "cppcheck.h"
|
||||
|
@ -69,10 +72,47 @@ void CheckThread::run()
|
|||
return;
|
||||
}
|
||||
|
||||
QString addonPath;
|
||||
if (QFileInfo(mDataDir + "/threadsafety.py").exists())
|
||||
addonPath = mDataDir;
|
||||
else if (QDir(mDataDir + "/addons").exists())
|
||||
addonPath = mDataDir + "/addons";
|
||||
else if (mDataDir.endsWith("/cfg")) {
|
||||
if (QDir(mDataDir.mid(0,mDataDir.size()-3) + "addons").exists())
|
||||
addonPath = mDataDir.mid(0,mDataDir.size()-3) + "addons";
|
||||
}
|
||||
|
||||
bool needDump = mAddons.contains("y2038") || mAddons.contains("threadsafety") || mAddons.contains("cert") || mAddons.contains("misra");
|
||||
QString file = mResult.getNextFile();
|
||||
while (!file.isEmpty() && mState == Running) {
|
||||
qDebug() << "Checking file" << file;
|
||||
mCppcheck.check(file.toStdString());
|
||||
if (!mAddons.isEmpty()) {
|
||||
if (needDump) {
|
||||
mCppcheck.settings().dump = true;
|
||||
mCppcheck.check(file.toStdString());
|
||||
mCppcheck.settings().dump = false;
|
||||
}
|
||||
foreach (const QString addon, mAddons) {
|
||||
if (addon == "clang")
|
||||
continue;
|
||||
QProcess process;
|
||||
QString a;
|
||||
if (QFileInfo(addonPath + '/' + addon + ".py").exists())
|
||||
a = addonPath + '/' + addon + ".py";
|
||||
else if (QFileInfo(addonPath + '/' + addon + '/' + addon + ".py").exists())
|
||||
a = addonPath + '/' + addon + '/' + addon + ".py";
|
||||
else
|
||||
continue;
|
||||
QString dumpFile = QString::fromStdString(file + ".dump");
|
||||
QString cmd = "python " + a + ' ' + dumpFile;
|
||||
qDebug() << cmd;
|
||||
process.start(cmd);
|
||||
process.waitForFinished();
|
||||
QString err(process.readAllStandardError());
|
||||
parseErrors(err, addon);
|
||||
}
|
||||
}
|
||||
emit fileChecked(file);
|
||||
|
||||
if (mState == Running)
|
||||
|
@ -84,6 +124,45 @@ void CheckThread::run()
|
|||
file = QString::fromStdString(fileSettings.filename);
|
||||
qDebug() << "Checking file" << file;
|
||||
mCppcheck.check(fileSettings);
|
||||
if (!mAddons.isEmpty()) {
|
||||
if (needDump) {
|
||||
mCppcheck.settings().dump = true;
|
||||
mCppcheck.check(fileSettings);
|
||||
mCppcheck.settings().dump = false;
|
||||
}
|
||||
foreach (const QString addon, mAddons) {
|
||||
QProcess process;
|
||||
if (addon == "clang") {
|
||||
QString cmd("clang --analyze");
|
||||
for (std::list<std::string>::const_iterator I = fileSettings.includePaths.begin(); I != fileSettings.includePaths.end(); ++I)
|
||||
cmd += " -I" + QString::fromStdString(*I);
|
||||
foreach (QString D, QString::fromStdString(fileSettings.defines).split(";"))
|
||||
cmd += " -D" + D;
|
||||
QString fileName = QString::fromStdString(fileSettings.filename);
|
||||
if (fileName.endsWith(".cpp"))
|
||||
cmd += " -std=c++11";
|
||||
cmd += ' ' + fileName;
|
||||
qDebug() << cmd;
|
||||
process.start(cmd);
|
||||
process.waitForFinished(600*1000);
|
||||
} else {
|
||||
QString a;
|
||||
if (QFileInfo(addonPath + '/' + addon + ".py").exists())
|
||||
a = addonPath + '/' + addon + ".py";
|
||||
else if (QFileInfo(addonPath + '/' + addon + '/' + addon + ".py").exists())
|
||||
a = addonPath + '/' + addon + '/' + addon + ".py";
|
||||
else
|
||||
continue;
|
||||
QString dumpFile = QString::fromStdString(fileSettings.filename + ".dump");
|
||||
QString cmd = "python " + a + ' ' + dumpFile;
|
||||
qDebug() << cmd;
|
||||
process.start(cmd);
|
||||
process.waitForFinished();
|
||||
}
|
||||
QString err(process.readAllStandardError());
|
||||
parseErrors(err, addon);
|
||||
}
|
||||
}
|
||||
emit fileChecked(file);
|
||||
|
||||
if (mState == Running)
|
||||
|
@ -103,3 +182,46 @@ void CheckThread::stop()
|
|||
mState = Stopping;
|
||||
mCppcheck.terminate();
|
||||
}
|
||||
|
||||
void CheckThread::parseErrors(QString err, QString tool)
|
||||
{
|
||||
QTextStream in(&err, QIODevice::ReadOnly);
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine();
|
||||
|
||||
if (tool == "clang") {
|
||||
QRegExp r("([^:]+):([0-9]+):[0-9]+: (warning|error): (.*)");
|
||||
if (!r.exactMatch(line))
|
||||
continue;
|
||||
const std::string filename = r.cap(1).toStdString();
|
||||
const int lineNumber = r.cap(2).toInt();
|
||||
Severity::SeverityType severity = (r.cap(3) == "error") ? Severity::error : Severity::warning;
|
||||
const std::string message = r.cap(4).toStdString();
|
||||
const std::string id = tool.toStdString();
|
||||
std::list<ErrorLogger::ErrorMessage::FileLocation> callstack;
|
||||
callstack.push_back(ErrorLogger::ErrorMessage::FileLocation(filename, lineNumber));
|
||||
ErrorLogger::ErrorMessage errmsg(callstack, filename, severity, message, id, false);
|
||||
mResult.reportErr(errmsg);
|
||||
} else {
|
||||
QRegExp r1("\\[([^:]+):([0-9]+)\\](.*)");
|
||||
if (!r1.exactMatch(line))
|
||||
continue;
|
||||
const std::string &filename = r1.cap(1).toStdString();
|
||||
const int lineNumber = r1.cap(2).toInt();
|
||||
|
||||
std::string message, id;
|
||||
QRegExp r2("(.*)\\[([a-zA-Z0-9\\-\\._]+)\\]");
|
||||
if (r2.exactMatch(r1.cap(3))) {
|
||||
message = r2.cap(1).toStdString();
|
||||
id = tool.toStdString() + '-' + r2.cap(2).toStdString();
|
||||
} else {
|
||||
message = r1.cap(3).toStdString();
|
||||
id = tool.toStdString();
|
||||
}
|
||||
std::list<ErrorLogger::ErrorMessage::FileLocation> callstack;
|
||||
callstack.push_back(ErrorLogger::ErrorMessage::FileLocation(filename, lineNumber));
|
||||
ErrorLogger::ErrorMessage errmsg(callstack, filename, Severity::style, message, id, false);
|
||||
mResult.reportErr(errmsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,14 @@ public:
|
|||
*/
|
||||
void analyseWholeProgram(const QStringList &files);
|
||||
|
||||
void setAddons(const QStringList &addons) {
|
||||
mAddons = addons;
|
||||
}
|
||||
|
||||
void setDataDir(const QString &dataDir) {
|
||||
mDataDir = dataDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief method that is run in a thread
|
||||
*
|
||||
|
@ -94,13 +102,16 @@ protected:
|
|||
ThreadResult &mResult;
|
||||
/**
|
||||
* @brief Cppcheck itself
|
||||
*
|
||||
*/
|
||||
CppCheck mCppcheck;
|
||||
|
||||
private:
|
||||
void parseErrors(QString err, QString tool);
|
||||
|
||||
QStringList mFiles;
|
||||
bool mAnalyseWholeProgram;
|
||||
QStringList mAddons;
|
||||
QString mDataDir;
|
||||
};
|
||||
/// @}
|
||||
#endif // CHECKTHREAD_H
|
||||
|
|
|
@ -66,6 +66,7 @@ MainWindow::MainWindow(TranslationHandler* th, QSettings* settings) :
|
|||
{
|
||||
mUI.setupUi(this);
|
||||
mThread = new ThreadHandler(this);
|
||||
mThread->setDataDir(mSettings->value("DATADIR", QString()).toString());
|
||||
mUI.mResults->initialize(mSettings, mApplications, mThread);
|
||||
|
||||
// Filter timer to delay filtering results slightly while typing
|
||||
|
@ -411,6 +412,8 @@ void MainWindow::doAnalyzeProject(ImportProject p)
|
|||
}
|
||||
|
||||
//mThread->SetanalyzeProject(true);
|
||||
if (mProjectFile)
|
||||
mThread->setAddons(mProjectFile->getAddons());
|
||||
mThread->setProject(p);
|
||||
mThread->check(checkSettings, true);
|
||||
}
|
||||
|
@ -1364,6 +1367,8 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile)
|
|||
QFileInfo inf(projectFile->getFilename());
|
||||
const QString rootpath = projectFile->getRootPath();
|
||||
|
||||
mThread->setAddons(projectFile->getAddons());
|
||||
|
||||
// If the root path is not given or is not "current dir", use project
|
||||
// file's location directory as root path
|
||||
if (rootpath.isEmpty() || rootpath == ".")
|
||||
|
|
|
@ -50,6 +50,8 @@ static const char LibrariesElementName[] = "libraries";
|
|||
static const char LibraryElementName[] = "library";
|
||||
static const char SuppressionsElementName[] = "suppressions";
|
||||
static const char SuppressionElementName[] = "suppression";
|
||||
static const char AddonElementName[] = "addon";
|
||||
static const char AddonsElementName[] = "addons";
|
||||
|
||||
ProjectFile::ProjectFile(QObject *parent) :
|
||||
QObject(parent)
|
||||
|
@ -122,6 +124,10 @@ bool ProjectFile::read(const QString &filename)
|
|||
if (insideProject && xmlReader.name() == SuppressionsElementName)
|
||||
readStringList(mSuppressions, xmlReader,SuppressionElementName);
|
||||
|
||||
// Addons
|
||||
if (insideProject && xmlReader.name() == AddonsElementName)
|
||||
readStringList(mAddons, xmlReader, AddonElementName);
|
||||
|
||||
break;
|
||||
|
||||
case QXmlStreamReader::EndElement:
|
||||
|
@ -433,6 +439,11 @@ void ProjectFile::setSuppressions(const QStringList &suppressions)
|
|||
mSuppressions = suppressions;
|
||||
}
|
||||
|
||||
void ProjectFile::setAddons(const QStringList &addons)
|
||||
{
|
||||
mAddons = addons;
|
||||
}
|
||||
|
||||
bool ProjectFile::write(const QString &filename)
|
||||
{
|
||||
if (!filename.isEmpty())
|
||||
|
@ -516,6 +527,11 @@ bool ProjectFile::write(const QString &filename)
|
|||
SuppressionsElementName,
|
||||
SuppressionElementName);
|
||||
|
||||
writeStringList(xmlWriter,
|
||||
mAddons,
|
||||
AddonsElementName,
|
||||
AddonElementName);
|
||||
|
||||
xmlWriter.writeEndDocument();
|
||||
file.close();
|
||||
return true;
|
||||
|
|
|
@ -110,6 +110,14 @@ public:
|
|||
return mSuppressions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get list addons.
|
||||
* @return list of addons.
|
||||
*/
|
||||
QStringList getAddons() const {
|
||||
return mAddons;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get filename for the project file.
|
||||
* @return file name.
|
||||
|
@ -171,6 +179,12 @@ public:
|
|||
*/
|
||||
void setSuppressions(const QStringList &suppressions);
|
||||
|
||||
/**
|
||||
* @brief Set list of addons.
|
||||
* @param addons List of addons.
|
||||
*/
|
||||
void setAddons(const QStringList &addons);
|
||||
|
||||
/**
|
||||
* @brief Write project file (to disk).
|
||||
* @param filename Filename to use.
|
||||
|
@ -297,6 +311,11 @@ private:
|
|||
* @brief List of suppressions.
|
||||
*/
|
||||
QStringList mSuppressions;
|
||||
|
||||
/**
|
||||
* @brief List of addons.
|
||||
*/
|
||||
QStringList mAddons;
|
||||
};
|
||||
/// @}
|
||||
#endif // PROJECT_FILE_H
|
||||
|
|
|
@ -141,6 +141,11 @@ void ProjectFileDialog::loadFromProjectFile(const ProjectFile *projectFile)
|
|||
setExcludedPaths(projectFile->getExcludedPaths());
|
||||
setLibraries(projectFile->getLibraries());
|
||||
setSuppressions(projectFile->getSuppressions());
|
||||
mUI.mAddonThreadSafety->setChecked(projectFile->getAddons().contains("threadsafety"));
|
||||
mUI.mAddonY2038->setChecked(projectFile->getAddons().contains("y2038"));
|
||||
mUI.mAddonCert->setChecked(projectFile->getAddons().contains("cert"));
|
||||
mUI.mAddonMisra->setChecked(projectFile->getAddons().contains("misra"));
|
||||
mUI.mClang->setChecked(projectFile->getAddons().contains("clang"));
|
||||
updatePathsAndDefines();
|
||||
}
|
||||
|
||||
|
@ -155,6 +160,18 @@ void ProjectFileDialog::saveToProjectFile(ProjectFile *projectFile) const
|
|||
projectFile->setExcludedPaths(getExcludedPaths());
|
||||
projectFile->setLibraries(getLibraries());
|
||||
projectFile->setSuppressions(getSuppressions());
|
||||
QStringList list;
|
||||
if (mUI.mAddonThreadSafety->isChecked())
|
||||
list << "threadsafety";
|
||||
if (mUI.mAddonY2038->isChecked())
|
||||
list << "y2038";
|
||||
if (mUI.mAddonCert->isChecked())
|
||||
list << "cert";
|
||||
if (mUI.mAddonMisra->isChecked())
|
||||
list << "misra";
|
||||
if (mUI.mClang->isChecked())
|
||||
list << "clang";
|
||||
projectFile->setAddons(list);
|
||||
}
|
||||
|
||||
void ProjectFileDialog::ok()
|
||||
|
@ -224,7 +241,7 @@ void ProjectFileDialog::browseImportProject()
|
|||
const QDir &dir = inf.absoluteDir();
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Import Project"),
|
||||
dir.canonicalPath(),
|
||||
tr("Visual Studio (*.sln *.vcxproj);;Compile database (compile_database.json)"));
|
||||
tr("Visual Studio (*.sln *.vcxproj);;Compile database (compile_commands.json)"));
|
||||
if (!fileName.isEmpty()) {
|
||||
mUI.mEditImportProject->setText(dir.relativeFilePath(fileName));
|
||||
updatePathsAndDefines();
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>642</width>
|
||||
<height>498</height>
|
||||
<height>507</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -463,6 +463,75 @@
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Addons</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_10">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mAddonY2038">
|
||||
<property name="text">
|
||||
<string>Y2038</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mAddonThreadSafety">
|
||||
<property name="text">
|
||||
<string>Thread safety</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Coding standards</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mAddonCert">
|
||||
<property name="text">
|
||||
<string>Cert</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mAddonMisra">
|
||||
<property name="text">
|
||||
<string>Misra</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Other</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mClang">
|
||||
<property name="text">
|
||||
<string>clang</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>368</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
|
|
@ -46,6 +46,7 @@ void ThreadHandler::clearFiles()
|
|||
mLastFiles.clear();
|
||||
mResults.clearFiles();
|
||||
mAnalyseWholeProgram = false;
|
||||
mAddons.clear();
|
||||
}
|
||||
|
||||
void ThreadHandler::setFiles(const QStringList &files)
|
||||
|
@ -91,6 +92,8 @@ void ThreadHandler::check(const Settings &settings, bool all)
|
|||
}
|
||||
|
||||
for (int i = 0; i < mRunningThreadCount; i++) {
|
||||
mThreads[i]->setAddons(mAddons);
|
||||
mThreads[i]->setDataDir(mDataDir);
|
||||
mThreads[i]->check(settings);
|
||||
}
|
||||
|
||||
|
@ -125,7 +128,6 @@ void ThreadHandler::setThreadCount(const int count)
|
|||
connect(mThreads.last(), &CheckThread::fileChecked,
|
||||
&mResults, &ThreadResult::fileChecked);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -71,6 +71,14 @@ public:
|
|||
*/
|
||||
void saveSettings(QSettings &settings) const;
|
||||
|
||||
void setAddons(const QStringList &addons) {
|
||||
mAddons = addons;
|
||||
}
|
||||
|
||||
void setDataDir(const QString &dataDir) {
|
||||
mDataDir = dataDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear all files from cppcheck
|
||||
*
|
||||
|
@ -236,6 +244,10 @@ protected:
|
|||
int mRunningThreadCount;
|
||||
|
||||
bool mAnalyseWholeProgram;
|
||||
|
||||
QStringList mAddons;
|
||||
|
||||
QString mDataDir;
|
||||
private:
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue