Check specific Visual Studio configurations (#2503)

This commit is contained in:
fuzzelhjb 2020-01-31 07:08:38 +01:00 committed by GitHub
parent 589b497ead
commit 074d08e39e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 208 additions and 11 deletions

View File

@ -65,6 +65,7 @@ void ProjectFile::clear()
mMaxCtuDepth = 10; mMaxCtuDepth = 10;
mCheckUnknownFunctionReturn.clear(); mCheckUnknownFunctionReturn.clear();
mSafeChecks.clear(); mSafeChecks.clear();
mVsConfigurations.clear();
} }
bool ProjectFile::read(const QString &filename) bool ProjectFile::read(const QString &filename)
@ -174,6 +175,9 @@ bool ProjectFile::read(const QString &filename)
if (xmlReader.name() == CppcheckXml::MaxCtuDepthElementName) if (xmlReader.name() == CppcheckXml::MaxCtuDepthElementName)
mMaxCtuDepth = readInt(xmlReader, mMaxCtuDepth); mMaxCtuDepth = readInt(xmlReader, mMaxCtuDepth);
// VSConfiguration
if (xmlReader.name() == CppcheckXml::VSConfigurationElementName)
readVsConfigurations(xmlReader);
break; break;
case QXmlStreamReader::EndElement: case QXmlStreamReader::EndElement:
@ -466,6 +470,44 @@ void ProjectFile::readExcludes(QXmlStreamReader &reader)
} while (!allRead); } while (!allRead);
} }
void ProjectFile::readVsConfigurations(QXmlStreamReader &reader)
{
QXmlStreamReader::TokenType type;
do {
type = reader.readNext();
switch (type) {
case QXmlStreamReader::StartElement:
// Read library-elements
if (reader.name().toString() == CppcheckXml::VSConfigurationName) {
QString config;
type = reader.readNext();
if (type == QXmlStreamReader::Characters) {
config = reader.text().toString();
}
mVsConfigurations << config;
}
break;
case QXmlStreamReader::EndElement:
if (reader.name().toString() != CppcheckXml::VSConfigurationName)
return;
break;
// Not handled
case QXmlStreamReader::NoToken:
case QXmlStreamReader::Invalid:
case QXmlStreamReader::StartDocument:
case QXmlStreamReader::EndDocument:
case QXmlStreamReader::Characters:
case QXmlStreamReader::Comment:
case QXmlStreamReader::DTD:
case QXmlStreamReader::EntityReference:
case QXmlStreamReader::ProcessingInstruction:
break;
}
} while (true);
}
void ProjectFile::readPlatform(QXmlStreamReader &reader) void ProjectFile::readPlatform(QXmlStreamReader &reader)
{ {
do { do {
@ -619,6 +661,11 @@ void ProjectFile::setAddons(const QStringList &addons)
mAddons = addons; mAddons = addons;
} }
void ProjectFile::setVSConfigurations(const QStringList &vsConfigs)
{
mVsConfigurations = vsConfigs;
}
bool ProjectFile::write(const QString &filename) bool ProjectFile::write(const QString &filename)
{ {
if (!filename.isEmpty()) if (!filename.isEmpty())
@ -694,6 +741,13 @@ bool ProjectFile::write(const QString &filename)
xmlWriter.writeEndElement(); xmlWriter.writeEndElement();
} }
if (!mVsConfigurations.isEmpty()) {
writeStringList(xmlWriter,
mVsConfigurations,
CppcheckXml::VSConfigurationElementName,
CppcheckXml::VSConfigurationName);
}
writeStringList(xmlWriter, writeStringList(xmlWriter,
mUndefines, mUndefines,
CppcheckXml::UndefinesElementName, CppcheckXml::UndefinesElementName,

View File

@ -124,6 +124,14 @@ public:
return ProjectFile::fromNativeSeparators(mExcludedPaths); return ProjectFile::fromNativeSeparators(mExcludedPaths);
} }
/**
* @brief Get list of paths to exclude from the check.
* @return list of paths.
*/
QStringList getVsConfigurations() const {
return mVsConfigurations;
}
/** /**
* @brief Get list libraries. * @brief Get list libraries.
* @return list of libraries. * @return list of libraries.
@ -272,6 +280,11 @@ public:
*/ */
void setAddons(const QStringList &addons); void setAddons(const QStringList &addons);
/** @brief Set list of Visual Studio configurations to be checked
* @param vsConfigs List of configurations
*/
void setVSConfigurations(const QStringList &vsConfigs);
/** /**
* @brief Set tags. * @brief Set tags.
* @param tags tag list * @param tags tag list
@ -394,6 +407,12 @@ protected:
*/ */
void readExcludes(QXmlStreamReader &reader); void readExcludes(QXmlStreamReader &reader);
/**
* @brief Read lists of Visual Studio configurations
* @param reader XML stream reader.
*/
void readVsConfigurations(QXmlStreamReader &reader);
/** /**
* @brief Read platform text. * @brief Read platform text.
* @param reader XML stream reader. * @param reader XML stream reader.
@ -458,6 +477,9 @@ private:
*/ */
bool mAnalyzeAllVsConfigs; bool mAnalyzeAllVsConfigs;
/** Check only a selected VS configuration */
QStringList mVsConfigurations;
/** Check code in headers */ /** Check code in headers */
bool mCheckHeaders; bool mCheckHeaders;

View File

@ -26,6 +26,7 @@
#include <QDir> #include <QDir>
#include <QSettings> #include <QSettings>
#include <QProcess> #include <QProcess>
#include <QListView>
#include "common.h" #include "common.h"
#include "newsuppressiondialog.h" #include "newsuppressiondialog.h"
#include "projectfiledialog.h" #include "projectfiledialog.h"
@ -33,6 +34,7 @@
#include "projectfile.h" #include "projectfile.h"
#include "library.h" #include "library.h"
#include "platforms.h" #include "platforms.h"
#include "importproject.h"
/** Return paths from QListWidget */ /** Return paths from QListWidget */
static QStringList getPaths(const QListWidget *list) static QStringList getPaths(const QListWidget *list)
@ -58,6 +60,16 @@ static const cppcheck::Platform::PlatformType builtinPlatforms[] = {
static const int numberOfBuiltinPlatforms = sizeof(builtinPlatforms) / sizeof(builtinPlatforms[0]); static const int numberOfBuiltinPlatforms = sizeof(builtinPlatforms) / sizeof(builtinPlatforms[0]);
QStringList ProjectFileDialog::getProjectConfigs(const QString &fileName) {
QStringList ret;
ImportProject importer;
Settings projSettings;
importer.import(fileName.toStdString(), &projSettings);
for (const std::string &cfg : importer.getVSConfigs())
ret << QString::fromStdString(cfg);
return ret;
}
ProjectFileDialog::ProjectFileDialog(ProjectFile *projectFile, QWidget *parent) ProjectFileDialog::ProjectFileDialog(ProjectFile *projectFile, QWidget *parent)
: QDialog(parent) : QDialog(parent)
, mProjectFile(projectFile) , mProjectFile(projectFile)
@ -194,7 +206,7 @@ ProjectFileDialog::ProjectFileDialog(ProjectFile *projectFile, QWidget *parent)
connect(mUI.mBtnRemoveSuppression, &QPushButton::clicked, this, &ProjectFileDialog::removeSuppression); connect(mUI.mBtnRemoveSuppression, &QPushButton::clicked, this, &ProjectFileDialog::removeSuppression);
connect(mUI.mListSuppressions, &QListWidget::doubleClicked, this, &ProjectFileDialog::editSuppression); connect(mUI.mListSuppressions, &QListWidget::doubleClicked, this, &ProjectFileDialog::editSuppression);
connect(mUI.mBtnBrowseMisraFile, &QPushButton::clicked, this, &ProjectFileDialog::browseMisraFile); connect(mUI.mBtnBrowseMisraFile, &QPushButton::clicked, this, &ProjectFileDialog::browseMisraFile);
connect(mUI.mChkAllVsConfigs, &QCheckBox::clicked, this, &ProjectFileDialog::checkAllVSConfigs);
loadFromProjectFile(projectFile); loadFromProjectFile(projectFile);
} }
@ -227,6 +239,13 @@ static void updateAddonCheckBox(QCheckBox *cb, const ProjectFile *projectFile, c
} }
} }
void ProjectFileDialog::checkAllVSConfigs()
{
if(mUI.mChkAllVsConfigs->isChecked())
mUI.mListVsConfigs->selectAll();
mUI.mListVsConfigs->setEnabled(!mUI.mChkAllVsConfigs->isChecked());
}
void ProjectFileDialog::loadFromProjectFile(const ProjectFile *projectFile) void ProjectFileDialog::loadFromProjectFile(const ProjectFile *projectFile)
{ {
setRootPath(projectFile->getRootPath()); setRootPath(projectFile->getRootPath());
@ -313,6 +332,16 @@ void ProjectFileDialog::loadFromProjectFile(const ProjectFile *projectFile)
} }
mUI.mEditTags->setText(projectFile->getTags().join(';')); mUI.mEditTags->setText(projectFile->getTags().join(';'));
updatePathsAndDefines(); updatePathsAndDefines();
if(mUI.mEditImportProject->text().endsWith(".sln") || mUI.mEditImportProject->text().endsWith(".vcxproj")) {
setVsConfigurations(getProjectConfigs(mUI.mEditImportProject->text()));
foreach(const QString &cfg, projectFile->getVsConfigurations()) {
QList<QListWidgetItem*> items = mUI.mListVsConfigs->findItems(cfg, Qt::MatchFlag::MatchExactly);
items[0]->setSelected(true);
}
}
else
mUI.mListVsConfigs->setEnabled(false);
} }
void ProjectFileDialog::saveToProjectFile(ProjectFile *projectFile) const void ProjectFileDialog::saveToProjectFile(ProjectFile *projectFile) const
@ -370,6 +399,7 @@ void ProjectFileDialog::saveToProjectFile(ProjectFile *projectFile) const
projectFile->setClangAnalyzer(mUI.mToolClangAnalyzer->isChecked()); projectFile->setClangAnalyzer(mUI.mToolClangAnalyzer->isChecked());
projectFile->setClangTidy(mUI.mToolClangTidy->isChecked()); projectFile->setClangTidy(mUI.mToolClangTidy->isChecked());
projectFile->setTags(mUI.mEditTags->text().split(";", QString::SkipEmptyParts)); projectFile->setTags(mUI.mEditTags->text().split(";", QString::SkipEmptyParts));
projectFile->setVSConfigurations(getVsConfigurations());
} }
void ProjectFileDialog::ok() void ProjectFileDialog::ok()
@ -429,6 +459,7 @@ void ProjectFileDialog::updatePathsAndDefines()
mUI.mBtnIncludeUp->setEnabled(!importProject); mUI.mBtnIncludeUp->setEnabled(!importProject);
mUI.mBtnIncludeDown->setEnabled(!importProject); mUI.mBtnIncludeDown->setEnabled(!importProject);
mUI.mChkAllVsConfigs->setEnabled(fileName.endsWith(".sln") || fileName.endsWith(".vcxproj")); mUI.mChkAllVsConfigs->setEnabled(fileName.endsWith(".sln") || fileName.endsWith(".vcxproj"));
mUI.mListVsConfigs->setEnabled(fileName.endsWith(".sln") || fileName.endsWith(".vcxproj"));
} }
void ProjectFileDialog::clearImportProject() void ProjectFileDialog::clearImportProject()
@ -451,9 +482,26 @@ void ProjectFileDialog::browseImportProject()
if (!fileName.isEmpty()) { if (!fileName.isEmpty()) {
mUI.mEditImportProject->setText(dir.relativeFilePath(fileName)); mUI.mEditImportProject->setText(dir.relativeFilePath(fileName));
updatePathsAndDefines(); updatePathsAndDefines();
setVsConfigurations(getProjectConfigs(fileName));
mUI.mListVsConfigs->selectAll();
} }
} }
QStringList ProjectFileDialog::getVsConfigurations() const
{
QStringList configs;
foreach(QListWidgetItem *item, mUI.mListVsConfigs->selectedItems())
configs << item->text();
return configs;
}
void ProjectFileDialog::setVsConfigurations(const QStringList &configs)
{
mUI.mListVsConfigs->clear();
mUI.mListVsConfigs->addItems(configs);
}
QString ProjectFileDialog::getImportProject() const QString ProjectFileDialog::getImportProject() const
{ {
return mUI.mEditImportProject->text(); return mUI.mEditImportProject->text();

View File

@ -58,6 +58,9 @@ private:
*/ */
QString getRootPath() const; QString getRootPath() const;
QStringList getVsConfigurations() const;
void setVsConfigurations(const QStringList &configs);
QString getImportProject() const; QString getImportProject() const;
/** Get Cppcheck build dir */ /** Get Cppcheck build dir */
@ -256,6 +259,11 @@ protected slots:
*/ */
void browseMisraFile(); void browseMisraFile();
/**
* @brief Check for all VS configurations
*/
void checkAllVSConfigs();
protected: protected:
/** /**
@ -295,6 +303,8 @@ protected:
int getSuppressionIndex(const QString &shortText) const; int getSuppressionIndex(const QString &shortText) const;
private: private:
QStringList getProjectConfigs(const QString &fileName);
Ui::ProjectFile mUI; Ui::ProjectFile mUI;
/** /**

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>888</width> <width>888</width>
<height>585</height> <height>573</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -64,14 +64,45 @@
</layout> </layout>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="mChkAllVsConfigs"> <layout class="QHBoxLayout" name="horizontalLayout_8">
<property name="toolTip"> <item>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;You have a choice:&lt;/p&gt;&lt;p&gt; * Analyze all Debug and Release configurations&lt;/p&gt;&lt;p&gt; * Only analyze the first matching Debug configuration&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <widget class="QCheckBox" name="mChkAllVsConfigs">
</property> <property name="toolTip">
<property name="text"> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;You have a choice:&lt;/p&gt;&lt;p&gt; * Analyze all Debug and Release configurations&lt;/p&gt;&lt;p&gt; * Only analyze the first matching Debug configuration&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>Analyze all Visual Studio configurations</string> </property>
</property> <property name="text">
</widget> <string>Analyze all Visual Studio configurations</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="mLabelVSConfig">
<property name="text">
<string>Selected VS Configurations</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="mListVsConfigs">
<property name="selectionMode">
<enum>QAbstractItemView::MultiSelection</enum>
</property>
</widget>
</item>
</layout>
</item> </item>
</layout> </layout>
</widget> </widget>

View File

@ -621,8 +621,10 @@ void ImportProject::importVcxproj(const std::string &filename, std::map<std::str
for (const tinyxml2::XMLElement *cfg = node->FirstChildElement(); cfg; cfg = cfg->NextSiblingElement()) { for (const tinyxml2::XMLElement *cfg = node->FirstChildElement(); cfg; cfg = cfg->NextSiblingElement()) {
if (std::strcmp(cfg->Name(), "ProjectConfiguration") == 0) { if (std::strcmp(cfg->Name(), "ProjectConfiguration") == 0) {
const ProjectConfiguration p(cfg); const ProjectConfiguration p(cfg);
if (p.platform != ProjectConfiguration::Unknown) if (p.platform != ProjectConfiguration::Unknown) {
projectConfigurationList.emplace_back(cfg); projectConfigurationList.emplace_back(cfg);
mAllVSConfigs.insert(p.configuration);
}
} }
} }
} else { } else {
@ -654,6 +656,18 @@ void ImportProject::importVcxproj(const std::string &filename, std::map<std::str
for (const std::string &c : compileList) { for (const std::string &c : compileList) {
for (const ProjectConfiguration &p : projectConfigurationList) { for (const ProjectConfiguration &p : projectConfigurationList) {
if (!guiProject.checkVsConfigs.empty()) {
bool doChecking = false;
for (std::string config : guiProject.checkVsConfigs)
if (config == p.configuration) {
doChecking = true;
break;
}
if(!doChecking)
continue;
}
FileSettings fs; FileSettings fs;
fs.filename = Path::simplifyPath(Path::isAbsolute(c) ? c : Path::getPathFromFilename(filename) + c); fs.filename = Path::simplifyPath(Path::isAbsolute(c) ? c : Path::getPathFromFilename(filename) + c);
fs.cfg = p.name; fs.cfg = p.name;
@ -975,6 +989,7 @@ static std::string istream_to_string(std::istream &istr)
return std::string(std::istreambuf_iterator<char>(istr), eos); return std::string(std::istreambuf_iterator<char>(istr), eos);
} }
bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *settings) bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *settings)
{ {
tinyxml2::XMLDocument doc; tinyxml2::XMLDocument doc;
@ -1018,6 +1033,8 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti
guiProject.libraries = readXmlStringList(node, "", CppcheckXml::LibraryElementName, nullptr); guiProject.libraries = readXmlStringList(node, "", CppcheckXml::LibraryElementName, nullptr);
else if (strcmp(node->Name(), CppcheckXml::SuppressionsElementName) == 0) else if (strcmp(node->Name(), CppcheckXml::SuppressionsElementName) == 0)
suppressions = readXmlStringList(node, "", CppcheckXml::SuppressionElementName, nullptr); suppressions = readXmlStringList(node, "", CppcheckXml::SuppressionElementName, nullptr);
else if (strcmp(node->Name(), CppcheckXml::VSConfigurationElementName) == 0)
guiProject.checkVsConfigs = readXmlStringList(node, "", CppcheckXml::VSConfigurationName, nullptr);
else if (strcmp(node->Name(), CppcheckXml::PlatformElementName) == 0) else if (strcmp(node->Name(), CppcheckXml::PlatformElementName) == 0)
guiProject.platform = node->GetText(); guiProject.platform = node->GetText();
else if (strcmp(node->Name(), CppcheckXml::AnalyzeAllVsConfigsElementName) == 0) else if (strcmp(node->Name(), CppcheckXml::AnalyzeAllVsConfigsElementName) == 0)
@ -1064,6 +1081,7 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti
settings->userUndefs = temp.userUndefs; settings->userUndefs = temp.userUndefs;
settings->addons = temp.addons; settings->addons = temp.addons;
settings->clangTidy = temp.clangTidy; settings->clangTidy = temp.clangTidy;
for (const std::string &p : paths) for (const std::string &p : paths)
guiProject.pathNames.push_back(p); guiProject.pathNames.push_back(p);
for (const std::string &supp : suppressions) for (const std::string &supp : suppressions)
@ -1103,3 +1121,8 @@ void ImportProject::selectOneVsConfig(Settings::PlatformType platform)
} }
} }
} }
std::list<std::string> ImportProject::getVSConfigs()
{
return std::list<std::string> (mAllVSConfigs.begin(), mAllVSConfigs.end());
}

View File

@ -84,12 +84,15 @@ public:
void selectOneVsConfig(cppcheck::Platform::PlatformType platform); void selectOneVsConfig(cppcheck::Platform::PlatformType platform);
std::list<std::string> getVSConfigs();
// Cppcheck GUI output // Cppcheck GUI output
struct { struct {
std::string analyzeAllVsConfigs; std::string analyzeAllVsConfigs;
std::vector<std::string> pathNames; std::vector<std::string> pathNames;
std::list<std::string> libraries; std::list<std::string> libraries;
std::list<std::string> excludedPaths; std::list<std::string> excludedPaths;
std::list<std::string> checkVsConfigs;
std::string projectFile; std::string projectFile;
std::string platform; std::string platform;
} guiProject; } guiProject;
@ -108,6 +111,7 @@ private:
void importBcb6Prj(const std::string &projectFilename); void importBcb6Prj(const std::string &projectFilename);
std::string mPath; std::string mPath;
std::set<std::string> mAllVSConfigs;
}; };
@ -154,6 +158,8 @@ namespace CppcheckXml {
const char CheckUnknownFunctionReturn[] = "check-unknown-function-return-values"; const char CheckUnknownFunctionReturn[] = "check-unknown-function-return-values";
const char ClangTidy[] = "clang-tidy"; const char ClangTidy[] = "clang-tidy";
const char Name[] = "name"; const char Name[] = "name";
const char VSConfigurationElementName[] = "vs-configurations";
const char VSConfigurationName[] = "config";
} }
/// @} /// @}

View File

@ -153,6 +153,9 @@ public:
for finding include files inside source files. (-I) */ for finding include files inside source files. (-I) */
std::list<std::string> includePaths; std::list<std::string> includePaths;
/** @brief List of selected Visual Studio configurations that should be checks */
std::list<std::string> checkVsConfigs;
/** @brief Inconclusive checks */ /** @brief Inconclusive checks */
bool inconclusive; bool inconclusive;