Skip to content

Commit dfc48be

Browse files
committed
Fixed danmar#2363 (GUI: Using addons in the checking)
1 parent 3c7f6cf commit dfc48be

File tree

9 files changed

+277
-4
lines changed

9 files changed

+277
-4
lines changed

gui/checkthread.cpp

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818

1919
#include <QString>
2020
#include <QDebug>
21+
#include <QDir>
22+
#include <QFileInfo>
23+
#include <QProcess>
2124
#include "checkthread.h"
2225
#include "threadresult.h"
2326
#include "cppcheck.h"
@@ -69,10 +72,47 @@ void CheckThread::run()
6972
return;
7073
}
7174

75+
QString addonPath;
76+
if (QFileInfo(mDataDir + "/threadsafety.py").exists())
77+
addonPath = mDataDir;
78+
else if (QDir(mDataDir + "/addons").exists())
79+
addonPath = mDataDir + "/addons";
80+
else if (mDataDir.endsWith("/cfg")) {
81+
if (QDir(mDataDir.mid(0,mDataDir.size()-3) + "addons").exists())
82+
addonPath = mDataDir.mid(0,mDataDir.size()-3) + "addons";
83+
}
84+
85+
bool needDump = mAddons.contains("y2038") || mAddons.contains("threadsafety") || mAddons.contains("cert") || mAddons.contains("misra");
7286
QString file = mResult.getNextFile();
7387
while (!file.isEmpty() && mState == Running) {
7488
qDebug() << "Checking file" << file;
7589
mCppcheck.check(file.toStdString());
90+
if (!mAddons.isEmpty()) {
91+
if (needDump) {
92+
mCppcheck.settings().dump = true;
93+
mCppcheck.check(file.toStdString());
94+
mCppcheck.settings().dump = false;
95+
}
96+
foreach (const QString addon, mAddons) {
97+
if (addon == "clang")
98+
continue;
99+
QProcess process;
100+
QString a;
101+
if (QFileInfo(addonPath + '/' + addon + ".py").exists())
102+
a = addonPath + '/' + addon + ".py";
103+
else if (QFileInfo(addonPath + '/' + addon + '/' + addon + ".py").exists())
104+
a = addonPath + '/' + addon + '/' + addon + ".py";
105+
else
106+
continue;
107+
QString dumpFile = QString::fromStdString(file + ".dump");
108+
QString cmd = "python " + a + ' ' + dumpFile;
109+
qDebug() << cmd;
110+
process.start(cmd);
111+
process.waitForFinished();
112+
QString err(process.readAllStandardError());
113+
parseErrors(err, addon);
114+
}
115+
}
76116
emit fileChecked(file);
77117

78118
if (mState == Running)
@@ -84,6 +124,45 @@ void CheckThread::run()
84124
file = QString::fromStdString(fileSettings.filename);
85125
qDebug() << "Checking file" << file;
86126
mCppcheck.check(fileSettings);
127+
if (!mAddons.isEmpty()) {
128+
if (needDump) {
129+
mCppcheck.settings().dump = true;
130+
mCppcheck.check(fileSettings);
131+
mCppcheck.settings().dump = false;
132+
}
133+
foreach (const QString addon, mAddons) {
134+
QProcess process;
135+
if (addon == "clang") {
136+
QString cmd("clang --analyze");
137+
for (std::list<std::string>::const_iterator I = fileSettings.includePaths.begin(); I != fileSettings.includePaths.end(); ++I)
138+
cmd += " -I" + QString::fromStdString(*I);
139+
foreach (QString D, QString::fromStdString(fileSettings.defines).split(";"))
140+
cmd += " -D" + D;
141+
QString fileName = QString::fromStdString(fileSettings.filename);
142+
if (fileName.endsWith(".cpp"))
143+
cmd += " -std=c++11";
144+
cmd += ' ' + fileName;
145+
qDebug() << cmd;
146+
process.start(cmd);
147+
process.waitForFinished(600*1000);
148+
} else {
149+
QString a;
150+
if (QFileInfo(addonPath + '/' + addon + ".py").exists())
151+
a = addonPath + '/' + addon + ".py";
152+
else if (QFileInfo(addonPath + '/' + addon + '/' + addon + ".py").exists())
153+
a = addonPath + '/' + addon + '/' + addon + ".py";
154+
else
155+
continue;
156+
QString dumpFile = QString::fromStdString(fileSettings.filename + ".dump");
157+
QString cmd = "python " + a + ' ' + dumpFile;
158+
qDebug() << cmd;
159+
process.start(cmd);
160+
process.waitForFinished();
161+
}
162+
QString err(process.readAllStandardError());
163+
parseErrors(err, addon);
164+
}
165+
}
87166
emit fileChecked(file);
88167

89168
if (mState == Running)
@@ -103,3 +182,46 @@ void CheckThread::stop()
103182
mState = Stopping;
104183
mCppcheck.terminate();
105184
}
185+
186+
void CheckThread::parseErrors(QString err, QString tool)
187+
{
188+
QTextStream in(&err, QIODevice::ReadOnly);
189+
while (!in.atEnd()) {
190+
QString line = in.readLine();
191+
192+
if (tool == "clang") {
193+
QRegExp r("([^:]+):([0-9]+):[0-9]+: (warning|error): (.*)");
194+
if (!r.exactMatch(line))
195+
continue;
196+
const std::string filename = r.cap(1).toStdString();
197+
const int lineNumber = r.cap(2).toInt();
198+
Severity::SeverityType severity = (r.cap(3) == "error") ? Severity::error : Severity::warning;
199+
const std::string message = r.cap(4).toStdString();
200+
const std::string id = tool.toStdString();
201+
std::list<ErrorLogger::ErrorMessage::FileLocation> callstack;
202+
callstack.push_back(ErrorLogger::ErrorMessage::FileLocation(filename, lineNumber));
203+
ErrorLogger::ErrorMessage errmsg(callstack, filename, severity, message, id, false);
204+
mResult.reportErr(errmsg);
205+
} else {
206+
QRegExp r1("\\[([^:]+):([0-9]+)\\](.*)");
207+
if (!r1.exactMatch(line))
208+
continue;
209+
const std::string &filename = r1.cap(1).toStdString();
210+
const int lineNumber = r1.cap(2).toInt();
211+
212+
std::string message, id;
213+
QRegExp r2("(.*)\\[([a-zA-Z0-9\\-\\._]+)\\]");
214+
if (r2.exactMatch(r1.cap(3))) {
215+
message = r2.cap(1).toStdString();
216+
id = tool.toStdString() + '-' + r2.cap(2).toStdString();
217+
} else {
218+
message = r1.cap(3).toStdString();
219+
id = tool.toStdString();
220+
}
221+
std::list<ErrorLogger::ErrorMessage::FileLocation> callstack;
222+
callstack.push_back(ErrorLogger::ErrorMessage::FileLocation(filename, lineNumber));
223+
ErrorLogger::ErrorMessage errmsg(callstack, filename, Severity::style, message, id, false);
224+
mResult.reportErr(errmsg);
225+
}
226+
}
227+
}

gui/checkthread.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ class CheckThread : public QThread {
5252
*/
5353
void analyseWholeProgram(const QStringList &files);
5454

55+
void setAddons(const QStringList &addons) {
56+
mAddons = addons;
57+
}
58+
59+
void setDataDir(const QString &dataDir) {
60+
mDataDir = dataDir;
61+
}
62+
5563
/**
5664
* @brief method that is run in a thread
5765
*
@@ -94,13 +102,16 @@ class CheckThread : public QThread {
94102
ThreadResult &mResult;
95103
/**
96104
* @brief Cppcheck itself
97-
*
98105
*/
99106
CppCheck mCppcheck;
100107

101108
private:
109+
void parseErrors(QString err, QString tool);
110+
102111
QStringList mFiles;
103112
bool mAnalyseWholeProgram;
113+
QStringList mAddons;
114+
QString mDataDir;
104115
};
105116
/// @}
106117
#endif // CHECKTHREAD_H

gui/mainwindow.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ MainWindow::MainWindow(TranslationHandler* th, QSettings* settings) :
6666
{
6767
mUI.setupUi(this);
6868
mThread = new ThreadHandler(this);
69+
mThread->setDataDir(mSettings->value("DATADIR", QString()).toString());
6970
mUI.mResults->initialize(mSettings, mApplications, mThread);
7071

7172
// Filter timer to delay filtering results slightly while typing
@@ -411,6 +412,8 @@ void MainWindow::doAnalyzeProject(ImportProject p)
411412
}
412413

413414
//mThread->SetanalyzeProject(true);
415+
if (mProjectFile)
416+
mThread->setAddons(mProjectFile->getAddons());
414417
mThread->setProject(p);
415418
mThread->check(checkSettings, true);
416419
}
@@ -1364,6 +1367,8 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile)
13641367
QFileInfo inf(projectFile->getFilename());
13651368
const QString rootpath = projectFile->getRootPath();
13661369

1370+
mThread->setAddons(projectFile->getAddons());
1371+
13671372
// If the root path is not given or is not "current dir", use project
13681373
// file's location directory as root path
13691374
if (rootpath.isEmpty() || rootpath == ".")

gui/projectfile.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ static const char LibrariesElementName[] = "libraries";
5050
static const char LibraryElementName[] = "library";
5151
static const char SuppressionsElementName[] = "suppressions";
5252
static const char SuppressionElementName[] = "suppression";
53+
static const char AddonElementName[] = "addon";
54+
static const char AddonsElementName[] = "addons";
5355

5456
ProjectFile::ProjectFile(QObject *parent) :
5557
QObject(parent)
@@ -122,6 +124,10 @@ bool ProjectFile::read(const QString &filename)
122124
if (insideProject && xmlReader.name() == SuppressionsElementName)
123125
readStringList(mSuppressions, xmlReader,SuppressionElementName);
124126

127+
// Addons
128+
if (insideProject && xmlReader.name() == AddonsElementName)
129+
readStringList(mAddons, xmlReader, AddonElementName);
130+
125131
break;
126132

127133
case QXmlStreamReader::EndElement:
@@ -433,6 +439,11 @@ void ProjectFile::setSuppressions(const QStringList &suppressions)
433439
mSuppressions = suppressions;
434440
}
435441

442+
void ProjectFile::setAddons(const QStringList &addons)
443+
{
444+
mAddons = addons;
445+
}
446+
436447
bool ProjectFile::write(const QString &filename)
437448
{
438449
if (!filename.isEmpty())
@@ -516,6 +527,11 @@ bool ProjectFile::write(const QString &filename)
516527
SuppressionsElementName,
517528
SuppressionElementName);
518529

530+
writeStringList(xmlWriter,
531+
mAddons,
532+
AddonsElementName,
533+
AddonElementName);
534+
519535
xmlWriter.writeEndDocument();
520536
file.close();
521537
return true;

gui/projectfile.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,14 @@ class ProjectFile : public QObject {
110110
return mSuppressions;
111111
}
112112

113+
/**
114+
* @brief Get list addons.
115+
* @return list of addons.
116+
*/
117+
QStringList getAddons() const {
118+
return mAddons;
119+
}
120+
113121
/**
114122
* @brief Get filename for the project file.
115123
* @return file name.
@@ -171,6 +179,12 @@ class ProjectFile : public QObject {
171179
*/
172180
void setSuppressions(const QStringList &suppressions);
173181

182+
/**
183+
* @brief Set list of addons.
184+
* @param addons List of addons.
185+
*/
186+
void setAddons(const QStringList &addons);
187+
174188
/**
175189
* @brief Write project file (to disk).
176190
* @param filename Filename to use.
@@ -297,6 +311,11 @@ class ProjectFile : public QObject {
297311
* @brief List of suppressions.
298312
*/
299313
QStringList mSuppressions;
314+
315+
/**
316+
* @brief List of addons.
317+
*/
318+
QStringList mAddons;
300319
};
301320
/// @}
302321
#endif // PROJECT_FILE_H

gui/projectfiledialog.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,11 @@ void ProjectFileDialog::loadFromProjectFile(const ProjectFile *projectFile)
141141
setExcludedPaths(projectFile->getExcludedPaths());
142142
setLibraries(projectFile->getLibraries());
143143
setSuppressions(projectFile->getSuppressions());
144+
mUI.mAddonThreadSafety->setChecked(projectFile->getAddons().contains("threadsafety"));
145+
mUI.mAddonY2038->setChecked(projectFile->getAddons().contains("y2038"));
146+
mUI.mAddonCert->setChecked(projectFile->getAddons().contains("cert"));
147+
mUI.mAddonMisra->setChecked(projectFile->getAddons().contains("misra"));
148+
mUI.mClang->setChecked(projectFile->getAddons().contains("clang"));
144149
updatePathsAndDefines();
145150
}
146151

@@ -155,6 +160,18 @@ void ProjectFileDialog::saveToProjectFile(ProjectFile *projectFile) const
155160
projectFile->setExcludedPaths(getExcludedPaths());
156161
projectFile->setLibraries(getLibraries());
157162
projectFile->setSuppressions(getSuppressions());
163+
QStringList list;
164+
if (mUI.mAddonThreadSafety->isChecked())
165+
list << "threadsafety";
166+
if (mUI.mAddonY2038->isChecked())
167+
list << "y2038";
168+
if (mUI.mAddonCert->isChecked())
169+
list << "cert";
170+
if (mUI.mAddonMisra->isChecked())
171+
list << "misra";
172+
if (mUI.mClang->isChecked())
173+
list << "clang";
174+
projectFile->setAddons(list);
158175
}
159176

160177
void ProjectFileDialog::ok()
@@ -224,7 +241,7 @@ void ProjectFileDialog::browseImportProject()
224241
const QDir &dir = inf.absoluteDir();
225242
QString fileName = QFileDialog::getOpenFileName(this, tr("Import Project"),
226243
dir.canonicalPath(),
227-
tr("Visual Studio (*.sln *.vcxproj);;Compile database (compile_database.json)"));
244+
tr("Visual Studio (*.sln *.vcxproj);;Compile database (compile_commands.json)"));
228245
if (!fileName.isEmpty()) {
229246
mUI.mEditImportProject->setText(dir.relativeFilePath(fileName));
230247
updatePathsAndDefines();

0 commit comments

Comments
 (0)