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)
{
mFiles.clear();
mCppcheck.settings() = settings;
start();
}
void CheckThread::AnalyseWholeProgram(const QStringList &files)
{
mFiles = files;
start();
}
void CheckThread::run()
{
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();
while (!file.isEmpty() && mState == Running) {
qDebug() << "Checking file" << file;

View File

@ -46,6 +46,12 @@ public:
*/
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
*
@ -91,7 +97,9 @@ protected:
*
*/
CppCheck mCppcheck;
private:
QStringList mFiles;
};
/// @}
#endif // CHECKTHREAD_H

View File

@ -438,6 +438,20 @@ void MainWindow::DoCheckFiles(const QStringList &files)
if (mProject)
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->Check(checkSettings, true);
}
@ -742,6 +756,12 @@ Settings MainWindow::GetCppcheckSettings()
// Only check the given -D configuration
if (!defines.isEmpty())
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.
@ -759,6 +779,8 @@ Settings MainWindow::GetCppcheckSettings()
result.addEnabled("portability");
result.addEnabled("information");
result.addEnabled("missingInclude");
if (!result.buildDir.empty())
result.addEnabled("unusedFunction");
result.debug = false;
result.debugwarnings = mSettings->value(SETTINGS_SHOW_DEBUG_WARNINGS, false).toBool();
result.quiet = false;

View File

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

View File

@ -27,6 +27,7 @@
static const char ProjectElementName[] = "project";
static const char ProjectVersionAttrib[] = "version";
static const char ProjectFileVersion[] = "1";
static const char BuildDirElementName[] = "builddir";
static const char ImportProjectElementName[] = "importproject";
static const char IncludeDirElementName[] = "includedir";
static const char DirElementName[] = "dir";
@ -84,6 +85,10 @@ bool ProjectFile::Read(const QString &filename)
if (insideProject && xmlReader.name() == RootPathName)
ReadRootPath(xmlReader);
// Read root path from inside project element
if (insideProject && xmlReader.name() == BuildDirElementName)
ReadBuildDir(xmlReader);
// Find paths to check from inside project element
if (insideProject && xmlReader.name() == PathsElementName)
ReadCheckPaths(xmlReader);
@ -152,6 +157,31 @@ void ProjectFile::ReadRootPath(QXmlStreamReader &reader)
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)
{
mImportProject.clear();
@ -426,6 +456,12 @@ bool ProjectFile::Write(const QString &filename)
xmlWriter.writeEndElement();
}
if (!mBuildDir.isEmpty()) {
xmlWriter.writeStartElement(BuildDirElementName);
xmlWriter.writeCharacters(mBuildDir);
xmlWriter.writeEndElement();
}
if (!mImportProject.isEmpty()) {
xmlWriter.writeStartElement(ImportProjectElementName);
xmlWriter.writeCharacters(mImportProject);

View File

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

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>615</width>
<height>357</height>
<width>635</width>
<height>368</height>
</rect>
</property>
<property name="windowTitle">
@ -41,6 +41,27 @@
</item>
</layout>
</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>
<spacer name="verticalSpacer_10">
<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.buildDirBrowse, SIGNAL(clicked()), this, SLOT(BrowseBuildDir()));
connect(mUI.mBrowseCompileDatabase, SIGNAL(clicked()), this, SLOT(BrowseCompileDatabase()));
connect(mUI.mBrowseVisualStudio, SIGNAL(clicked()), this, SLOT(BrowseVisualStudio()));
connect(mUI.mBtnAddInclude, SIGNAL(clicked()), this, SLOT(AddIncludeDir()));
@ -119,6 +120,38 @@ void ProjectFileDialog::SaveSettings() const
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()
{
const QFileInfo inf(mFilePath);
@ -180,6 +213,10 @@ QString ProjectFileDialog::GetRootPath() const
return root;
}
QString ProjectFileDialog::GetBuildDir() const {
return mUI.buildDirEdit->text();
}
QString ProjectFileDialog::GetImportProject() const
{
return mUI.mEditCompileDatabase->text() + mUI.mEditVisualStudio->text();
@ -253,10 +290,12 @@ QStringList ProjectFileDialog::GetSuppressions() const
return suppressions;
}
void ProjectFileDialog::SetRootPath(const QString &root)
{
QString newroot = QDir::toNativeSeparators(root);
mUI.mEditProjectRoot->setText(newroot);
void ProjectFileDialog::SetRootPath(const QString &root) {
mUI.mEditProjectRoot->setText(QDir::toNativeSeparators(root));
}
void ProjectFileDialog::SetBuildDir(const QString &buildDir) {
mUI.buildDirEdit->setText(buildDir);
}
void ProjectFileDialog::SetImportProject(const QString &importProject)
@ -321,38 +360,16 @@ void ProjectFileDialog::SetSuppressions(const QStringList &suppressions)
void ProjectFileDialog::AddIncludeDir()
{
const QFileInfo inf(mFilePath);
const QString rootpath = inf.absolutePath();
QString selectedDir = QFileDialog::getExistingDirectory(this,
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);
}
const QString dir = getExistingDirectory(tr("Select include directory"), true);
if (!dir.isEmpty())
AddIncludeDir(dir);
}
void ProjectFileDialog::AddPath()
{
QFileInfo inf(mFilePath);
const QString rootpath = inf.absolutePath();
QString selectedDir = QFileDialog::getExistingDirectory(this,
tr("Select a directory to check"),
rootpath);
if (!selectedDir.isEmpty()) {
AddPath(selectedDir);
}
QString dir = getExistingDirectory(tr("Select a directory to check"), false);
if (!dir.isEmpty())
AddPath(dir);
}
void ProjectFileDialog::RemoveIncludeDir()
@ -383,18 +400,9 @@ void ProjectFileDialog::RemovePath()
void ProjectFileDialog::AddExcludePath()
{
QFileInfo inf(mFilePath);
const QString rootpath = inf.absolutePath();
QString selectedDir = QFileDialog::getExistingDirectory(this,
tr("Select directory to ignore"),
rootpath);
if (!selectedDir.isEmpty()) {
if (!selectedDir.endsWith('/'))
selectedDir += '/';
AddExcludePath(selectedDir);
}
QString dir = getExistingDirectory(tr("Select directory to ignore"), true);
if (!dir.isEmpty())
AddExcludePath(dir);
}
void ProjectFileDialog::EditExcludePath()

View File

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

View File

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

View File

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