diff --git a/.github/workflows/selfcheck.yml b/.github/workflows/selfcheck.yml index 1adcc540cf9..389e39371ba 100644 --- a/.github/workflows/selfcheck.yml +++ b/.github/workflows/selfcheck.yml @@ -121,7 +121,7 @@ jobs: - name: Self check (unusedFunction / no test / no gui) run: | - supprs="--suppress=unusedFunction:lib/errorlogger.h:197 --suppress=unusedFunction:lib/importproject.cpp:1660 --suppress=unusedFunction:lib/importproject.cpp:1684" + supprs="--suppress=unusedFunction:lib/errorlogger.h:197 --suppress=unusedFunction:lib/importproject.cpp:1665 --suppress=unusedFunction:lib/importproject.cpp:1689" ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib -D__CPPCHECK__ -D__GNUC__ --enable=unusedFunction,information --exception-handling -rp=. --project=cmake.output.notest_nogui/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr $supprs env: DISABLE_VALUEFLOW: 1 diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 161eec381b3..c3ca1672768 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -1126,6 +1126,8 @@ bool MainWindow::getCppcheckSettings(Settings& settings, Suppressions& supprs) for (const QString& undefine : undefines) settings.userUndefs.insert(undefine.toStdString()); + settings.userIncludes.push_back(mProjectFile->getUserInclude().toStdString()); + const QStringList libraries = mProjectFile->getLibraries(); for (const QString& library : libraries) { settings.libraries.emplace_back(library.toStdString()); diff --git a/gui/projectfile.cpp b/gui/projectfile.cpp index b807723ceeb..ce2d066fd71 100644 --- a/gui/projectfile.cpp +++ b/gui/projectfile.cpp @@ -63,6 +63,7 @@ void ProjectFile::clear() mIncludeDirs.clear(); mDefines.clear(); mUndefines.clear(); + mUserInclude.clear(); mPaths.clear(); mExcludedPaths.clear(); mLibraries.clear(); @@ -166,6 +167,9 @@ bool ProjectFile::read(const QString &filename) if (xmlReader.name() == QString(CppcheckXml::UndefinesElementName)) readStringList(mUndefines, xmlReader, CppcheckXml::UndefineName); + if (xmlReader.name() == QString(CppcheckXml::UserIncludeElementName)) + mUserInclude = readString(xmlReader); + // Find exclude list from inside project element if (xmlReader.name() == QString(CppcheckXml::ExcludeElementName)) readExcludes(xmlReader); @@ -347,15 +351,13 @@ bool ProjectFile::readBool(QXmlStreamReader &reader) int ProjectFile::readInt(QXmlStreamReader &reader, int defaultValue) { - int ret = defaultValue; do { const QXmlStreamReader::TokenType type = reader.readNext(); switch (type) { case QXmlStreamReader::Characters: - ret = reader.text().toString().toInt(); - FALLTHROUGH; + return reader.text().toString().toInt(); case QXmlStreamReader::EndElement: - return ret; + return defaultValue; // Not handled case QXmlStreamReader::StartElement: case QXmlStreamReader::NoToken: @@ -373,15 +375,13 @@ int ProjectFile::readInt(QXmlStreamReader &reader, int defaultValue) QString ProjectFile::readString(QXmlStreamReader &reader) { - QString ret; do { const QXmlStreamReader::TokenType type = reader.readNext(); switch (type) { case QXmlStreamReader::Characters: - ret = reader.text().toString(); - FALLTHROUGH; + return reader.text().toString(); case QXmlStreamReader::EndElement: - return ret; + return {}; // Not handled case QXmlStreamReader::StartElement: case QXmlStreamReader::NoToken: @@ -910,6 +910,12 @@ bool ProjectFile::write(const QString &filename) xmlWriter.writeEndElement(); } + if (!mUserInclude.isEmpty()) { + xmlWriter.writeStartElement(CppcheckXml::UserIncludeElementName); + xmlWriter.writeCharacters(mUserInclude); + xmlWriter.writeEndElement(); + } + if (!mVsConfigurations.isEmpty()) { writeStringList(xmlWriter, mVsConfigurations, diff --git a/gui/projectfile.h b/gui/projectfile.h index e7f8d342180..f46374b74fa 100644 --- a/gui/projectfile.h +++ b/gui/projectfile.h @@ -141,6 +141,14 @@ class ProjectFile : public QObject { return mUndefines; } + const QString& getUserInclude() const { + return mUserInclude; + } + + void setUserInclude(const QString& userInclude) { + mUserInclude = userInclude; + } + /** * @brief Get list of paths to check. * @return list of paths. @@ -601,6 +609,9 @@ class ProjectFile : public QObject { */ QStringList mUndefines; + /** @brief --include file */ + QString mUserInclude; + /** * @brief List of paths to check. */ diff --git a/gui/projectfile.ui b/gui/projectfile.ui index 4bd01339d83..5543e67910c 100644 --- a/gui/projectfile.ui +++ b/gui/projectfile.ui @@ -7,7 +7,7 @@ 0 0 940 - 701 + 741 @@ -80,7 +80,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -95,7 +95,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -117,7 +117,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -151,7 +151,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -199,7 +199,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -269,7 +269,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -284,7 +284,7 @@ - QAbstractItemView::SelectRows + QAbstractItemView::SelectionBehavior::SelectRows @@ -314,7 +314,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -342,10 +342,38 @@ + + + + + + Include file + + + mEditUserInclude + + + + + + + <html><head/><body><p><span style=" font-family:'monospace'; color:#000000; background-color:#ffffff;">Force inclusion of a header file</span></p></body></html> + + + + + + + Browse.. + + + + + - Qt::Vertical + Qt::Orientation::Vertical @@ -552,7 +580,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -586,7 +614,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -701,7 +729,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -744,7 +772,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -769,7 +797,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -856,7 +884,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -919,7 +947,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1018,7 +1046,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -1035,10 +1063,10 @@ - Qt::Horizontal + Qt::Orientation::Horizontal - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok diff --git a/gui/projectfiledialog.cpp b/gui/projectfiledialog.cpp index d46eb5c3489..82fc0aac7c4 100644 --- a/gui/projectfiledialog.cpp +++ b/gui/projectfiledialog.cpp @@ -235,6 +235,7 @@ ProjectFileDialog::ProjectFileDialog(ProjectFile *projectFile, bool premium, QWi connect(mUI->mBtnBrowseBuildDir, &QPushButton::clicked, this, &ProjectFileDialog::browseBuildDir); connect(mUI->mBtnClearImportProject, &QPushButton::clicked, this, &ProjectFileDialog::clearImportProject); connect(mUI->mBtnBrowseImportProject, &QPushButton::clicked, this, &ProjectFileDialog::browseImportProject); + connect(mUI->mBtnBrowseUserInclude, &QPushButton::clicked, this, &ProjectFileDialog::browseUserInclude); connect(mUI->mBtnAddCheckPath, SIGNAL(clicked()), this, SLOT(addCheckPath())); connect(mUI->mBtnEditCheckPath, &QPushButton::clicked, this, &ProjectFileDialog::editCheckPath); connect(mUI->mBtnRemoveCheckPath, &QPushButton::clicked, this, &ProjectFileDialog::removeCheckPath); @@ -303,6 +304,7 @@ void ProjectFileDialog::loadFromProjectFile(const ProjectFile *projectFile) setIncludepaths(projectFile->getIncludeDirs()); setDefines(projectFile->getDefines()); setUndefines(projectFile->getUndefines()); + mUI->mEditUserInclude->setText(projectFile->getUserInclude()); setCheckPaths(projectFile->getCheckPaths()); setImportProject(projectFile->getImportProject()); mUI->mChkAllVsConfigs->setChecked(projectFile->getAnalyzeAllVsConfigs()); @@ -481,6 +483,7 @@ void ProjectFileDialog::saveToProjectFile(ProjectFile *projectFile) const projectFile->setIncludes(getIncludePaths()); projectFile->setDefines(getDefines()); projectFile->setUndefines(getUndefines()); + projectFile->setUserInclude(mUI->mEditUserInclude->text()); projectFile->setCheckPaths(getCheckPaths()); projectFile->setExcludedPaths(getExcludedPaths()); projectFile->setLibraries(getLibraries()); @@ -643,6 +646,21 @@ void ProjectFileDialog::browseImportProject() } } +void ProjectFileDialog::browseUserInclude() +{ + const QFileInfo inf(mProjectFile->getFilename()); + const QDir &dir = inf.absoluteDir(); + QMap filters; + filters[tr("C/C++ header")] = "*.h"; + filters[tr("All files")] = "*.*"; + QString fileName = QFileDialog::getOpenFileName(this, tr("Include file"), + dir.canonicalPath(), + toFilterString(filters)); + if (!fileName.isEmpty()) { + mUI->mEditUserInclude->setText(dir.relativeFilePath(fileName)); + } +} + QStringList ProjectFileDialog::getProjectConfigurations() const { QStringList configs; diff --git a/gui/projectfiledialog.h b/gui/projectfiledialog.h index 68f62ea83e5..231d1f26ef3 100644 --- a/gui/projectfiledialog.h +++ b/gui/projectfiledialog.h @@ -201,6 +201,11 @@ private slots: */ void browseImportProject(); + /** + * @brief Browse for include file + */ + void browseUserInclude(); + /** * @brief Add new path to check. */ diff --git a/lib/importproject.cpp b/lib/importproject.cpp index 401f1334b81..ac19db922ed 100644 --- a/lib/importproject.cpp +++ b/lib/importproject.cpp @@ -1484,6 +1484,10 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings &setti else if (strcmp(name, CppcheckXml::UndefinesElementName) == 0) { for (const std::string &u : readXmlStringList(node, "", CppcheckXml::UndefineName, nullptr)) temp.userUndefs.insert(u); + } else if (strcmp(name, CppcheckXml::UserIncludeElementName) == 0) { + const char* i = node->GetText(); + if (i) + temp.userIncludes.emplace_back(i); } else if (strcmp(name, CppcheckXml::ImportProjectElementName) == 0) { const std::string t_str = empty_if_null(node->GetText()); if (!t_str.empty()) @@ -1605,6 +1609,7 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings &setti settings.includePaths = temp.includePaths; // TODO: append instead of overwrite settings.userDefines = temp.userDefines; // TODO: append instead of overwrite settings.userUndefs = temp.userUndefs; // TODO: append instead of overwrite + settings.userIncludes = temp.userIncludes; // TODO: append instead of overwrite for (const std::string &addon : temp.addons) settings.addons.emplace(addon); settings.clang = temp.clang; diff --git a/lib/importproject.h b/lib/importproject.h index 4a6e318c02d..fb724b5b454 100644 --- a/lib/importproject.h +++ b/lib/importproject.h @@ -151,6 +151,7 @@ namespace CppcheckXml { static constexpr char DefineNameAttrib[] = "name"; static constexpr char UndefinesElementName[] = "undefines"; static constexpr char UndefineName[] = "undefine"; + static constexpr char UserIncludeElementName[] = "user-include"; static constexpr char PathsElementName[] = "paths"; static constexpr char PathName[] = "dir"; static constexpr char PathNameAttrib[] = "name"; diff --git a/test/testimportproject.cpp b/test/testimportproject.cpp index f7c53f3d3a6..6f8633dbeea 100644 --- a/test/testimportproject.cpp +++ b/test/testimportproject.cpp @@ -482,6 +482,7 @@ class TestImportProject : public TestFixture { " \n" " \n" " \n" + " gcc-macros.h\n" " \n" " \n" " \n" @@ -497,6 +498,8 @@ class TestImportProject : public TestFixture { ASSERT_EQUALS("cli/", project.guiProject.pathNames[0]); ASSERT_EQUALS(1, s.includePaths.size()); ASSERT_EQUALS("lib/", s.includePaths.front()); + ASSERT_EQUALS(1, s.userIncludes.size()); + ASSERT_EQUALS("gcc-macros.h", s.userIncludes.front()); ASSERT_EQUALS(true, s.inlineSuppressions); }