GUI: Add cppcheck build dir

This commit is contained in:
Daniel Marjamäki 2016-11-19 20:38:50 +01:00
parent 1235815ae9
commit 84e6163cb8
11 changed files with 237 additions and 91 deletions

View File

@ -37,14 +37,35 @@ CheckThread::~CheckThread()
void CheckThread::Check(const Settings &settings) void CheckThread::Check(const Settings &settings)
{ {
mFiles.clear();
mCppcheck.settings() = settings; mCppcheck.settings() = settings;
start(); start();
} }
void CheckThread::AnalyseWholeProgram(const QStringList &files)
{
mFiles = files;
start();
}
void CheckThread::run() void CheckThread::run()
{ {
mState = Running; mState = Running;
if (!mFiles.isEmpty()) {
qDebug() << "Whole program analysis";
const std::string &buildDir = mCppcheck.settings().buildDir;
if (!buildDir.empty()) {
std::map<std::string,std::size_t> files2;
for (QString file : mFiles)
files2[file.toStdString()] = 0;
mCppcheck.analyseWholeProgram(buildDir, files2);
}
mFiles.clear();
emit Done();
return;
}
QString file = mResult.GetNextFile(); QString file = mResult.GetNextFile();
while (!file.isEmpty() && mState == Running) { while (!file.isEmpty() && mState == Running) {
qDebug() << "Checking file" << file; qDebug() << "Checking file" << file;

View File

@ -46,6 +46,12 @@ public:
*/ */
void Check(const Settings &settings); void Check(const Settings &settings);
/**
* @brief Run whole program analysis
* @param files All files
*/
void AnalyseWholeProgram(const QStringList &files);
/** /**
* @brief method that is run in a thread * @brief method that is run in a thread
* *
@ -91,7 +97,9 @@ protected:
* *
*/ */
CppCheck mCppcheck; CppCheck mCppcheck;
private: private:
QStringList mFiles;
}; };
/// @} /// @}
#endif // CHECKTHREAD_H #endif // CHECKTHREAD_H

View File

@ -438,6 +438,20 @@ void MainWindow::DoCheckFiles(const QStringList &files)
if (mProject) if (mProject)
qDebug() << "Checking project file" << mProject->GetProjectFile()->GetFilename(); qDebug() << "Checking project file" << mProject->GetProjectFile()->GetFilename();
if (!checkSettings.buildDir.empty()) {
QString s = QString::fromStdString(checkSettings.buildDir);
if (!s.endsWith('/'))
s += '/';
s += "files.txt";
std::ofstream fout(s.toStdString());
if (fout.is_open()) {
foreach (QString f, fileNames) {
fout << f.toStdString() << '\n';
}
}
}
mThread->SetCheckFiles(true); mThread->SetCheckFiles(true);
mThread->Check(checkSettings, true); mThread->Check(checkSettings, true);
} }
@ -742,6 +756,12 @@ Settings MainWindow::GetCppcheckSettings()
// Only check the given -D configuration // Only check the given -D configuration
if (!defines.isEmpty()) if (!defines.isEmpty())
result.maxConfigs = 1; result.maxConfigs = 1;
QString buildDir = pfile->GetBuildDir();
if (!buildDir.isEmpty()) {
QString prjpath = QFileInfo(pfile->GetFilename()).absolutePath();
result.buildDir = (prjpath + '/' + buildDir).toStdString();
}
} }
// Include directories (and files) are searched in listed order. // Include directories (and files) are searched in listed order.
@ -759,6 +779,8 @@ Settings MainWindow::GetCppcheckSettings()
result.addEnabled("portability"); result.addEnabled("portability");
result.addEnabled("information"); result.addEnabled("information");
result.addEnabled("missingInclude"); result.addEnabled("missingInclude");
if (!result.buildDir.empty())
result.addEnabled("unusedFunction");
result.debug = false; result.debug = false;
result.debugwarnings = mSettings->value(SETTINGS_SHOW_DEBUG_WARNINGS, false).toBool(); result.debugwarnings = mSettings->value(SETTINGS_SHOW_DEBUG_WARNINGS, false).toBool();
result.quiet = false; result.quiet = false;

View File

@ -86,53 +86,40 @@ bool Project::Open()
bool Project::Edit() bool Project::Edit()
{ {
ProjectFileDialog dlg(mFilename, mParentWidget); ProjectFileDialog dlg(mFilename, mParentWidget);
QString root = mPFile->GetRootPath(); dlg.SetRootPath(mPFile->GetRootPath());
dlg.SetRootPath(root); dlg.SetBuildDir(mPFile->GetBuildDir());
QStringList includes = mPFile->GetIncludeDirs(); dlg.SetIncludepaths(mPFile->GetIncludeDirs());
dlg.SetIncludepaths(includes); dlg.SetDefines(mPFile->GetDefines());
QStringList defines = mPFile->GetDefines(); dlg.SetPaths(mPFile->GetCheckPaths());
dlg.SetDefines(defines); dlg.SetImportProject(mPFile->GetImportProject());
QStringList paths = mPFile->GetCheckPaths(); dlg.SetExcludedPaths(mPFile->GetExcludedPaths());
dlg.SetPaths(paths); dlg.SetLibraries(mPFile->GetLibraries());
QString importProject = mPFile->GetImportProject(); dlg.SetSuppressions(mPFile->GetSuppressions());
dlg.SetImportProject(importProject);
QStringList ignorepaths = mPFile->GetExcludedPaths();
dlg.SetExcludedPaths(ignorepaths);
QStringList libraries = mPFile->GetLibraries();
dlg.SetLibraries(libraries);
QStringList suppressions = mPFile->GetSuppressions();
dlg.SetSuppressions(suppressions);
int rv = dlg.exec(); if (dlg.exec() != QDialog::Accepted)
if (rv == QDialog::Accepted) { return false;
QString root = dlg.GetRootPath();
mPFile->SetRootPath(root);
mPFile->SetImportProject(dlg.GetImportProject());
QStringList includes = dlg.GetIncludePaths();
mPFile->SetIncludes(includes);
QStringList defines = dlg.GetDefines();
mPFile->SetDefines(defines);
QStringList paths = dlg.GetPaths();
mPFile->SetCheckPaths(paths);
QStringList excludedpaths = dlg.GetExcludedPaths();
mPFile->SetExcludedPaths(excludedpaths);
QStringList libraries = dlg.GetLibraries();
mPFile->SetLibraries(libraries);
QStringList suppressions = dlg.GetSuppressions();
mPFile->SetSuppressions(suppressions);
bool writeSuccess = mPFile->Write(); mPFile->SetRootPath(dlg.GetRootPath());
if (!writeSuccess) { mPFile->SetBuildDir(dlg.GetBuildDir());
QMessageBox msg(QMessageBox::Critical, mPFile->SetImportProject(dlg.GetImportProject());
tr("Cppcheck"), mPFile->SetIncludes(dlg.GetIncludePaths());
tr("Could not write the project file."), mPFile->SetDefines(dlg.GetDefines());
QMessageBox::Ok, mPFile->SetCheckPaths(dlg.GetPaths());
mParentWidget); mPFile->SetExcludedPaths(dlg.GetExcludedPaths());
msg.exec(); mPFile->SetLibraries(dlg.GetLibraries());
} mPFile->SetSuppressions(dlg.GetSuppressions());
return writeSuccess;
if (!mPFile->Write()) {
QMessageBox msg(QMessageBox::Critical,
tr("Cppcheck"),
tr("Could not write the project file."),
QMessageBox::Ok,
mParentWidget);
msg.exec();
return false;
} }
return false;
return true;
} }
void Project::Create() void Project::Create()

View File

@ -27,6 +27,7 @@
static const char ProjectElementName[] = "project"; static const char ProjectElementName[] = "project";
static const char ProjectVersionAttrib[] = "version"; static const char ProjectVersionAttrib[] = "version";
static const char ProjectFileVersion[] = "1"; static const char ProjectFileVersion[] = "1";
static const char BuildDirElementName[] = "builddir";
static const char ImportProjectElementName[] = "importproject"; static const char ImportProjectElementName[] = "importproject";
static const char IncludeDirElementName[] = "includedir"; static const char IncludeDirElementName[] = "includedir";
static const char DirElementName[] = "dir"; static const char DirElementName[] = "dir";
@ -84,6 +85,10 @@ bool ProjectFile::Read(const QString &filename)
if (insideProject && xmlReader.name() == RootPathName) if (insideProject && xmlReader.name() == RootPathName)
ReadRootPath(xmlReader); ReadRootPath(xmlReader);
// Read root path from inside project element
if (insideProject && xmlReader.name() == BuildDirElementName)
ReadBuildDir(xmlReader);
// Find paths to check from inside project element // Find paths to check from inside project element
if (insideProject && xmlReader.name() == PathsElementName) if (insideProject && xmlReader.name() == PathsElementName)
ReadCheckPaths(xmlReader); ReadCheckPaths(xmlReader);
@ -152,6 +157,31 @@ void ProjectFile::ReadRootPath(QXmlStreamReader &reader)
mRootPath = name; mRootPath = name;
} }
void ProjectFile::ReadBuildDir(QXmlStreamReader &reader)
{
mBuildDir.clear();
do {
const QXmlStreamReader::TokenType type = reader.readNext();
switch (type) {
case QXmlStreamReader::Characters:
mBuildDir = reader.text().toString();
case QXmlStreamReader::EndElement:
return;
// Not handled
case QXmlStreamReader::StartElement:
case QXmlStreamReader::NoToken:
case QXmlStreamReader::Invalid:
case QXmlStreamReader::StartDocument:
case QXmlStreamReader::EndDocument:
case QXmlStreamReader::Comment:
case QXmlStreamReader::DTD:
case QXmlStreamReader::EntityReference:
case QXmlStreamReader::ProcessingInstruction:
break;
}
} while (1);
}
void ProjectFile::ReadImportProject(QXmlStreamReader &reader) void ProjectFile::ReadImportProject(QXmlStreamReader &reader)
{ {
mImportProject.clear(); mImportProject.clear();
@ -426,6 +456,12 @@ bool ProjectFile::Write(const QString &filename)
xmlWriter.writeEndElement(); xmlWriter.writeEndElement();
} }
if (!mBuildDir.isEmpty()) {
xmlWriter.writeStartElement(BuildDirElementName);
xmlWriter.writeCharacters(mBuildDir);
xmlWriter.writeEndElement();
}
if (!mImportProject.isEmpty()) { if (!mImportProject.isEmpty()) {
xmlWriter.writeStartElement(ImportProjectElementName); xmlWriter.writeStartElement(ImportProjectElementName);
xmlWriter.writeCharacters(mImportProject); xmlWriter.writeCharacters(mImportProject);

View File

@ -54,6 +54,10 @@ public:
return mRootPath; return mRootPath;
} }
QString GetBuildDir() const {
return mBuildDir;
}
QString GetImportProject() const { QString GetImportProject() const {
return mImportProject; return mImportProject;
} }
@ -122,6 +126,11 @@ public:
mRootPath = rootpath; mRootPath = rootpath;
} }
void SetBuildDir(const QString &buildDir) {
mBuildDir = buildDir;
}
void SetImportProject(const QString &importProject) { void SetImportProject(const QString &importProject) {
mImportProject = importProject; mImportProject = importProject;
} }
@ -193,6 +202,8 @@ protected:
*/ */
void ReadRootPath(QXmlStreamReader &reader); void ReadRootPath(QXmlStreamReader &reader);
void ReadBuildDir(QXmlStreamReader &reader);
/** /**
* @brief Read importproject from XML. * @brief Read importproject from XML.
* @param reader XML stream reader. * @param reader XML stream reader.
@ -251,6 +262,10 @@ private:
*/ */
QString mRootPath; QString mRootPath;
/** Cppcheck build dir */
QString mBuildDir;
/** Visual studio project/solution , compile database */
QString mImportProject; QString mImportProject;
/** /**

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>615</width> <width>635</width>
<height>357</height> <height>368</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -41,6 +41,27 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QLabel" name="buildDirLabel">
<property name="text">
<string>Cppcheck build dir (optional)</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="buildDirEdit"/>
</item>
<item>
<widget class="QPushButton" name="buildDirBrowse">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<spacer name="verticalSpacer_10"> <spacer name="verticalSpacer_10">
<property name="orientation"> <property name="orientation">

View File

@ -83,6 +83,7 @@ ProjectFileDialog::ProjectFileDialog(const QString &path, QWidget *parent)
} }
connect(mUI.mButtons, SIGNAL(accepted()), this, SLOT(accept())); connect(mUI.mButtons, SIGNAL(accepted()), this, SLOT(accept()));
connect(mUI.buildDirBrowse, SIGNAL(clicked()), this, SLOT(BrowseBuildDir()));
connect(mUI.mBrowseCompileDatabase, SIGNAL(clicked()), this, SLOT(BrowseCompileDatabase())); connect(mUI.mBrowseCompileDatabase, SIGNAL(clicked()), this, SLOT(BrowseCompileDatabase()));
connect(mUI.mBrowseVisualStudio, SIGNAL(clicked()), this, SLOT(BrowseVisualStudio())); connect(mUI.mBrowseVisualStudio, SIGNAL(clicked()), this, SLOT(BrowseVisualStudio()));
connect(mUI.mBtnAddInclude, SIGNAL(clicked()), this, SLOT(AddIncludeDir())); connect(mUI.mBtnAddInclude, SIGNAL(clicked()), this, SLOT(AddIncludeDir()));
@ -119,6 +120,38 @@ void ProjectFileDialog::SaveSettings() const
settings.setValue(SETTINGS_PROJECT_DIALOG_HEIGHT, size().height()); settings.setValue(SETTINGS_PROJECT_DIALOG_HEIGHT, size().height());
} }
QString ProjectFileDialog::getExistingDirectory(const QString &caption, bool trailingSlash) {
const QFileInfo inf(mFilePath);
const QString rootpath = inf.absolutePath();
QString selectedDir = QFileDialog::getExistingDirectory(this,
caption,
rootpath);
if (selectedDir.isEmpty())
return QString();
// Check if the path is relative to project file's path and if so
// make it a relative path instead of absolute path.
const QDir dir(rootpath);
const QString relpath(dir.relativeFilePath(selectedDir));
if (!relpath.startsWith("."))
selectedDir = relpath;
// Trailing slash..
if (trailingSlash && !selectedDir.endsWith('/'))
selectedDir += '/';
return selectedDir;
}
void ProjectFileDialog::BrowseBuildDir()
{
const QString dir(getExistingDirectory(tr("Select Cppcheck build dir"), false));
if (!dir.isEmpty())
mUI.buildDirEdit->setText(dir);
}
void ProjectFileDialog::BrowseCompileDatabase() void ProjectFileDialog::BrowseCompileDatabase()
{ {
const QFileInfo inf(mFilePath); const QFileInfo inf(mFilePath);
@ -180,6 +213,10 @@ QString ProjectFileDialog::GetRootPath() const
return root; return root;
} }
QString ProjectFileDialog::GetBuildDir() const {
return mUI.buildDirEdit->text();
}
QString ProjectFileDialog::GetImportProject() const QString ProjectFileDialog::GetImportProject() const
{ {
return mUI.mEditCompileDatabase->text() + mUI.mEditVisualStudio->text(); return mUI.mEditCompileDatabase->text() + mUI.mEditVisualStudio->text();
@ -253,10 +290,12 @@ QStringList ProjectFileDialog::GetSuppressions() const
return suppressions; return suppressions;
} }
void ProjectFileDialog::SetRootPath(const QString &root) void ProjectFileDialog::SetRootPath(const QString &root) {
{ mUI.mEditProjectRoot->setText(QDir::toNativeSeparators(root));
QString newroot = QDir::toNativeSeparators(root); }
mUI.mEditProjectRoot->setText(newroot);
void ProjectFileDialog::SetBuildDir(const QString &buildDir) {
mUI.buildDirEdit->setText(buildDir);
} }
void ProjectFileDialog::SetImportProject(const QString &importProject) void ProjectFileDialog::SetImportProject(const QString &importProject)
@ -321,38 +360,16 @@ void ProjectFileDialog::SetSuppressions(const QStringList &suppressions)
void ProjectFileDialog::AddIncludeDir() void ProjectFileDialog::AddIncludeDir()
{ {
const QFileInfo inf(mFilePath); const QString dir = getExistingDirectory(tr("Select include directory"), true);
const QString rootpath = inf.absolutePath(); if (!dir.isEmpty())
QString selectedDir = QFileDialog::getExistingDirectory(this, AddIncludeDir(dir);
tr("Select include directory"),
rootpath);
if (!selectedDir.isEmpty()) {
// Check if the path is relative to project file's path and if so
// make it a relative path instead of absolute path.
const QDir dir(selectedDir);
QString absPath = dir.absolutePath();
if (absPath.startsWith(rootpath)) {
// Remove also the slash from begin of new relative path
selectedDir = absPath.remove(0, rootpath.length() + 1);
}
if (!selectedDir.endsWith("/"))
selectedDir += '/';
AddIncludeDir(selectedDir);
}
} }
void ProjectFileDialog::AddPath() void ProjectFileDialog::AddPath()
{ {
QFileInfo inf(mFilePath); QString dir = getExistingDirectory(tr("Select a directory to check"), false);
const QString rootpath = inf.absolutePath(); if (!dir.isEmpty())
QString selectedDir = QFileDialog::getExistingDirectory(this, AddPath(dir);
tr("Select a directory to check"),
rootpath);
if (!selectedDir.isEmpty()) {
AddPath(selectedDir);
}
} }
void ProjectFileDialog::RemoveIncludeDir() void ProjectFileDialog::RemoveIncludeDir()
@ -383,18 +400,9 @@ void ProjectFileDialog::RemovePath()
void ProjectFileDialog::AddExcludePath() void ProjectFileDialog::AddExcludePath()
{ {
QFileInfo inf(mFilePath); QString dir = getExistingDirectory(tr("Select directory to ignore"), true);
const QString rootpath = inf.absolutePath(); if (!dir.isEmpty())
AddExcludePath(dir);
QString selectedDir = QFileDialog::getExistingDirectory(this,
tr("Select directory to ignore"),
rootpath);
if (!selectedDir.isEmpty()) {
if (!selectedDir.endsWith('/'))
selectedDir += '/';
AddExcludePath(selectedDir);
}
} }
void ProjectFileDialog::EditExcludePath() void ProjectFileDialog::EditExcludePath()

View File

@ -49,6 +49,9 @@ public:
QString GetImportProject() const; QString GetImportProject() const;
/** Get Cppcheck build dir */
QString GetBuildDir() const;
/** /**
* @brief Return include paths from the dialog control. * @brief Return include paths from the dialog control.
* @return List of include paths. * @return List of include paths.
@ -91,6 +94,9 @@ public:
*/ */
void SetRootPath(const QString &root); void SetRootPath(const QString &root);
/** Set build dir */
void SetBuildDir(const QString &buildDir);
void SetImportProject(const QString &importProject); void SetImportProject(const QString &importProject);
/** /**
@ -131,6 +137,11 @@ public:
protected slots: protected slots:
/**
* @brief Browse for build dir.
*/
void BrowseBuildDir();
/** /**
* @brief Browse for Visual Studio solution/project. * @brief Browse for Visual Studio solution/project.
*/ */
@ -247,6 +258,8 @@ private:
/** @brief Library checkboxes */ /** @brief Library checkboxes */
QList<QCheckBox*> mLibraryCheckboxes; QList<QCheckBox*> mLibraryCheckboxes;
QString getExistingDirectory(const QString &caption, bool trailingSlash);
}; };
/// @} /// @}

View File

@ -29,7 +29,9 @@
ThreadHandler::ThreadHandler(QObject *parent) : ThreadHandler::ThreadHandler(QObject *parent) :
QObject(parent), QObject(parent),
mScanDuration(0), mScanDuration(0),
mRunningThreadCount(0) mRunningThreadCount(0),
mAnalyseWholeProgram(false)
{ {
SetThreadCount(1); SetThreadCount(1);
} }
@ -43,6 +45,7 @@ void ThreadHandler::ClearFiles()
{ {
mLastFiles.clear(); mLastFiles.clear();
mResults.ClearFiles(); mResults.ClearFiles();
mAnalyseWholeProgram = false;
} }
void ThreadHandler::SetFiles(const QStringList &files) void ThreadHandler::SetFiles(const QStringList &files)
@ -94,6 +97,8 @@ void ThreadHandler::Check(const Settings &settings, bool all)
// Date and time when checking starts.. // Date and time when checking starts..
mCheckStartTime = QDateTime::currentDateTime(); mCheckStartTime = QDateTime::currentDateTime();
mAnalyseWholeProgram = true;
mTime.start(); mTime.start();
} }
@ -137,10 +142,17 @@ void ThreadHandler::RemoveThreads()
} }
mThreads.clear(); mThreads.clear();
mAnalyseWholeProgram = false;
} }
void ThreadHandler::ThreadDone() void ThreadHandler::ThreadDone()
{ {
if (mRunningThreadCount == 1 && mAnalyseWholeProgram) {
mThreads[0]->AnalyseWholeProgram(mLastFiles);
mAnalyseWholeProgram = false;
return;
}
mRunningThreadCount--; mRunningThreadCount--;
if (mRunningThreadCount == 0) { if (mRunningThreadCount == 0) {
emit Done(); emit Done();
@ -158,6 +170,7 @@ void ThreadHandler::ThreadDone()
void ThreadHandler::Stop() void ThreadHandler::Stop()
{ {
mCheckStartTime = QDateTime(); mCheckStartTime = QDateTime();
mAnalyseWholeProgram = false;
for (int i = 0; i < mThreads.size(); i++) { for (int i = 0; i < mThreads.size(); i++) {
mThreads[i]->stop(); mThreads[i]->stop();
} }

View File

@ -234,6 +234,8 @@ protected:
* *
*/ */
int mRunningThreadCount; int mRunningThreadCount;
bool mAnalyseWholeProgram;
private: private:
/** /**