diff --git a/gui/checkthread.cpp b/gui/checkthread.cpp index e22709ee7..d5c0635c5 100644 --- a/gui/checkthread.cpp +++ b/gui/checkthread.cpp @@ -127,6 +127,9 @@ void CheckThread::runAddonsAndTools(const ImportProject::FileSettings *fileSetti foreach (QString D, QString::fromStdString(fileSettings->defines).split(";")) { args << ("-D" + D); } + foreach (const std::string& U, fileSettings->undefs) { + args << QString::fromStdString("-U" + U); + } const QString clangPath = CheckThread::clangTidyCmd(); if (!clangPath.isEmpty()) { diff --git a/gui/cppchecklibrarydata.cpp b/gui/cppchecklibrarydata.cpp index 4f02bace2..5208c4b91 100644 --- a/gui/cppchecklibrarydata.cpp +++ b/gui/cppchecklibrarydata.cpp @@ -91,6 +91,11 @@ static CppcheckLibraryData::Define loadDefine(const QXmlStreamReader &xmlReader) return define; } +static QString loadUndefine(const QXmlStreamReader &xmlReader) +{ + return xmlReader.attributes().value("name").toString(); +} + static CppcheckLibraryData::Function::Arg loadFunctionArg(QXmlStreamReader &xmlReader) { CppcheckLibraryData::Function::Arg arg; @@ -237,6 +242,8 @@ QString CppcheckLibraryData::open(QIODevice &file) containers.append(loadContainer(xmlReader)); else if (elementName == "define") defines.append(loadDefine(xmlReader)); + else if (elementName == "undefine") + undefines.append(loadUndefine(xmlReader)); else if (elementName == "function") functions.append(loadFunction(xmlReader, comments)); else if (elementName == "memory" || elementName == "resource") @@ -459,6 +466,12 @@ QString CppcheckLibraryData::toString() const xmlWriter.writeEndElement(); } + foreach (const QString &undef, undefines) { + xmlWriter.writeStartElement("undefine"); + xmlWriter.writeAttribute("name", undef); + xmlWriter.writeEndElement(); + } + foreach (const Function &function, functions) { writeFunction(xmlWriter, function); } diff --git a/gui/cppchecklibrarydata.h b/gui/cppchecklibrarydata.h index 6b0be5714..1792ce72d 100644 --- a/gui/cppchecklibrarydata.h +++ b/gui/cppchecklibrarydata.h @@ -154,6 +154,7 @@ public: void clear() { containers.clear(); defines.clear(); + undefines.clear(); functions.clear(); memoryresource.clear(); podtypes.clear(); @@ -163,6 +164,7 @@ public: void swap(CppcheckLibraryData &other) { containers.swap(other.containers); defines.swap(other.defines); + undefines.swap(other.undefines); functions.swap(other.functions); memoryresource.swap(other.memoryresource); podtypes.swap(other.podtypes); @@ -176,6 +178,7 @@ public: QList functions; QList memoryresource; QList podtypes; + QStringList undefines; }; #endif // LIBRARYDATA_H diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 537a0a8f7..9f60593e1 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -838,6 +838,10 @@ Settings MainWindow::getCppcheckSettings() result.userDefines += define.toStdString(); } + const QStringList undefines = mProjectFile->getUndefines(); + foreach (QString undefine, undefines) + result.userUndefs.insert(undefine.toStdString()); + const QStringList libraries = mProjectFile->getLibraries(); foreach (QString library, libraries) { const QString filename = library + ".cfg"; diff --git a/gui/projectfile.cpp b/gui/projectfile.cpp index 04c32f7cd..922001bf7 100644 --- a/gui/projectfile.cpp +++ b/gui/projectfile.cpp @@ -37,6 +37,8 @@ static const char DirNameAttrib[] = "name"; static const char DefinesElementName[] = "defines"; static const char DefineName[] = "define"; static const char DefineNameAttrib[] = "name"; +static const char UndefinesElementName[] = "undefines"; +static const char UndefineName[] = "undefine"; static const char PathsElementName[] = "paths"; static const char PathName[] = "dir"; static const char PathNameAttrib[] = "name"; @@ -82,6 +84,7 @@ void ProjectFile::clear() mAnalyzeAllVsConfigs = true; mIncludeDirs.clear(); mDefines.clear(); + mUndefines.clear(); mPaths.clear(); mExcludedPaths.clear(); mLibraries.clear(); @@ -138,6 +141,10 @@ bool ProjectFile::read(const QString &filename) if (insideProject && xmlReader.name() == DefinesElementName) readDefines(xmlReader); + // Find preprocessor define from inside project element + if (insideProject && xmlReader.name() == UndefinesElementName) + readStringList(mUndefines, xmlReader, UndefineName); + // Find exclude list from inside project element if (insideProject && xmlReader.name() == ExcludeElementName) readExcludes(xmlReader); @@ -557,6 +564,11 @@ void ProjectFile::setDefines(const QStringList &defines) mDefines = defines; } +void ProjectFile::setUndefines(const QStringList &undefines) +{ + mUndefines = undefines; +} + void ProjectFile::setCheckPaths(const QStringList &paths) { mPaths = paths; @@ -650,6 +662,11 @@ bool ProjectFile::write(const QString &filename) xmlWriter.writeEndElement(); } + writeStringList(xmlWriter, + mUndefines, + UndefinesElementName, + UndefineName); + if (!mPaths.isEmpty()) { xmlWriter.writeStartElement(PathsElementName); foreach (QString path, mPaths) { diff --git a/gui/projectfile.h b/gui/projectfile.h index c31e93d24..d8a39406f 100644 --- a/gui/projectfile.h +++ b/gui/projectfile.h @@ -84,6 +84,14 @@ public: return mDefines; } + /** + * @brief Get list of undefines. + * @return list of undefines. + */ + QStringList getUndefines() const { + return mUndefines; + } + /** * @brief Get list of paths to check. * @return list of paths. @@ -198,6 +206,12 @@ public: */ void setDefines(const QStringList &defines); + /** + * @brief Set list of undefines. + * @param defines List of undefines. + */ + void setUndefines(const QStringList &undefines); + /** * @brief Set list of paths to check. * @param paths List of paths. @@ -372,6 +386,11 @@ private: */ QStringList mDefines; + /** + * @brief List of undefines. + */ + QStringList mUndefines; + /** * @brief List of paths to check. */ diff --git a/gui/projectfiledialog.cpp b/gui/projectfiledialog.cpp index 90a1d8a83..a49c84d69 100644 --- a/gui/projectfiledialog.cpp +++ b/gui/projectfiledialog.cpp @@ -134,6 +134,9 @@ ProjectFileDialog::ProjectFileDialog(ProjectFile *projectFile, QWidget *parent) mUI.mEditTags->setValidator(new QRegExpValidator(QRegExp("[a-zA-Z0-9 ;]*"),this)); + const QRegExp undefRegExp("\\s*([a-zA-Z_][a-zA-Z0-9_]*[; ]*)*"); + mUI.mEditUndefines->setValidator(new QRegExpValidator(undefRegExp, this)); + connect(mUI.mButtons, &QDialogButtonBox::accepted, this, &ProjectFileDialog::ok); connect(mUI.mBtnBrowseBuildDir, &QPushButton::clicked, this, &ProjectFileDialog::browseBuildDir); connect(mUI.mBtnClearImportProject, &QPushButton::clicked, this, &ProjectFileDialog::clearImportProject); @@ -192,6 +195,7 @@ void ProjectFileDialog::loadFromProjectFile(const ProjectFile *projectFile) setBuildDir(projectFile->getBuildDir()); setIncludepaths(projectFile->getIncludeDirs()); setDefines(projectFile->getDefines()); + setUndefines(projectFile->getUndefines()); setCheckPaths(projectFile->getCheckPaths()); setImportProject(projectFile->getImportProject()); mUI.mChkAllVsConfigs->setChecked(projectFile->getAnalyzeAllVsConfigs()); @@ -268,6 +272,7 @@ void ProjectFileDialog::saveToProjectFile(ProjectFile *projectFile) const projectFile->setAnalyzeAllVsConfigs(mUI.mChkAllVsConfigs->isChecked()); projectFile->setIncludes(getIncludePaths()); projectFile->setDefines(getDefines()); + projectFile->setUndefines(getUndefines()); projectFile->setCheckPaths(getCheckPaths()); projectFile->setExcludedPaths(getExcludedPaths()); projectFile->setLibraries(getLibraries()); @@ -348,6 +353,7 @@ void ProjectFileDialog::updatePathsAndDefines() mUI.mBtnEditCheckPath->setEnabled(!importProject); mUI.mBtnRemoveCheckPath->setEnabled(!importProject); mUI.mEditDefines->setEnabled(!importProject); + mUI.mEditUndefines->setEnabled(!importProject); mUI.mBtnAddInclude->setEnabled(!importProject); mUI.mBtnEditInclude->setEnabled(!importProject); mUI.mBtnRemoveInclude->setEnabled(!importProject); @@ -456,6 +462,14 @@ QStringList ProjectFileDialog::getDefines() const return defines; } +QStringList ProjectFileDialog::getUndefines() const +{ + const QString undefine = mUI.mEditUndefines->text().trimmed(); + QStringList undefines = undefine.split(QRegExp("\\s*;\\s*"), QString::SkipEmptyParts); + undefines.removeDuplicates(); + return undefines; +} + QStringList ProjectFileDialog::getCheckPaths() const { const int count = mUI.mListCheckPaths->count(); @@ -524,6 +538,11 @@ void ProjectFileDialog::setDefines(const QStringList &defines) mUI.mEditDefines->setText(definestr); } +void ProjectFileDialog::setUndefines(const QStringList &undefines) +{ + mUI.mEditUndefines->setText(undefines.join(";")); +} + void ProjectFileDialog::setCheckPaths(const QStringList &paths) { foreach (QString path, paths) { diff --git a/gui/projectfiledialog.h b/gui/projectfiledialog.h index 8870efe06..8ce0982f9 100644 --- a/gui/projectfiledialog.h +++ b/gui/projectfiledialog.h @@ -75,6 +75,12 @@ private: */ QStringList getDefines() const; + /** + * @brief Return undefine names from the dialog control. + * @return List of undefine names. + */ + QStringList getUndefines() const; + /** * @brief Return check paths from the dialog control. * @return List of check paths. @@ -124,6 +130,12 @@ private: */ void setDefines(const QStringList &defines); + /** + * @brief Set undefine names to dialog control. + * @param defines List of undefine names to set to dialog control. + */ + void setUndefines(const QStringList &defines); + /** * @brief Set check paths to dialog control. * @param paths List of path names to set to dialog control. diff --git a/gui/projectfiledialog.ui b/gui/projectfiledialog.ui index 530155444..606b01718 100644 --- a/gui/projectfiledialog.ui +++ b/gui/projectfiledialog.ui @@ -166,6 +166,27 @@ + + + + + + Undefines: + + + mEditUndefines + + + + + + + Undefines must be separated by a semicolon. Example: UNDEF1;UNDEF2;UNDEF3 + + + + + diff --git a/gui/stats.ui b/gui/stats.ui index 0c630abff..8147b8e7e 100644 --- a/gui/stats.ui +++ b/gui/stats.ui @@ -125,6 +125,26 @@ + + + + Undefines: + + + + + + + + 0 + 0 + + + + true + + + diff --git a/gui/statsdialog.cpp b/gui/statsdialog.cpp index 67da168f1..5e95b15eb 100644 --- a/gui/statsdialog.cpp +++ b/gui/statsdialog.cpp @@ -50,6 +50,7 @@ void StatsDialog::setProject(const ProjectFile* projectFile) mUI.mPaths->setText(projectFile->getCheckPaths().join(";")); mUI.mIncludePaths->setText(projectFile->getIncludeDirs().join(";")); mUI.mDefines->setText(projectFile->getDefines().join(";")); + mUI.mUndefines->setText(projectFile->getUndefines().join(";")); #ifndef HAVE_QCHART mUI.mTabHistory->setVisible(false); #else @@ -81,6 +82,7 @@ void StatsDialog::setProject(const ProjectFile* projectFile) mUI.mPaths->setText(QString()); mUI.mIncludePaths->setText(QString()); mUI.mDefines->setText(QString()); + mUI.mUndefines->setText(QString()); } } @@ -174,6 +176,7 @@ void StatsDialog::copyToClipboard() const QString paths(tr("Paths")); const QString incPaths(tr("Include paths")); const QString defines(tr("Defines")); + const QString undefines(tr("Undefines")); const QString prevScan(tr("Previous Scan")); const QString selPath(tr("Path selected")); const QString numFiles(tr("Number of files scanned")); @@ -193,6 +196,7 @@ void StatsDialog::copyToClipboard() "\t%4:\t%5\n" "\t%6:\t%7\n" "\t%8:\t%9\n" + "\t%10:\t%11\n" ) .arg(projSettings) .arg(project) @@ -202,7 +206,9 @@ void StatsDialog::copyToClipboard() .arg(incPaths) .arg(mUI.mIncludePaths->text()) .arg(defines) - .arg(mUI.mDefines->text()); + .arg(mUI.mDefines->text()) + .arg(undefines) + .arg(mUI.mUndefines->text()); const QString previous = QString( "%1\n" @@ -251,6 +257,7 @@ void StatsDialog::copyToClipboard() " %4:%5\n" " %6:%7\n" " %8:%9\n" + " %10:%11\n" "\n" ) .arg(projSettings) @@ -261,7 +268,9 @@ void StatsDialog::copyToClipboard() .arg(incPaths) .arg(mUI.mIncludePaths->text()) .arg(defines) - .arg(mUI.mDefines->text()); + .arg(mUI.mDefines->text()) + .arg(undefines) + .arg(mUI.mUndefines->text()); const QString htmlPrevious = QString( "

%1

\n" diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 9bf215177..d2fd333b1 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -97,7 +97,7 @@ unsigned int CppCheck::check(const ImportProject::FileSettings &fs) temp.mSettings.userDefines += ';'; temp.mSettings.userDefines += fs.cppcheckDefines(); temp.mSettings.includePaths = fs.includePaths; - // TODO: temp.mSettings.userUndefs = fs.undefs; + temp.mSettings.userUndefs = fs.undefs; if (fs.platformType != Settings::Unspecified) { temp.mSettings.platform(fs.platformType); } @@ -123,7 +123,14 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string mErrorLogger.reportOut(std::string("Checking ") + fixedpath + ' ' + cfgname + std::string("...")); if (mSettings.verbose) { - mErrorLogger.reportOut("Defines: " + mSettings.userDefines); + mErrorLogger.reportOut("Defines:" + mSettings.userDefines); + std::string undefs; + for (const std::string& U : mSettings.userUndefs) { + if (!undefs.empty()) + undefs += ';'; + undefs += ' ' + U; + } + mErrorLogger.reportOut("Undefines:" + undefs); std::string includePaths; for (const std::string &I : mSettings.includePaths) includePaths += " -I" + I;