diff --git a/.github/workflows/CI-unixish-docker.yml b/.github/workflows/CI-unixish-docker.yml index c5e51d5b4c0..8e54e5dce28 100644 --- a/.github/workflows/CI-unixish-docker.yml +++ b/.github/workflows/CI-unixish-docker.yml @@ -60,8 +60,10 @@ jobs: # needs to be called after the package installation since # - it doesn't call "apt-get update" # - it doesn't support centos + # + # needs to be to fixated on 1.2.11 so it works with older images - see https://github.com/hendrikmuhs/ccache-action/issues/178 - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 + uses: hendrikmuhs/ccache-action@v1.2.11 if: matrix.image != 'ubuntu:14.04' # no support for --set-config with: key: ${{ github.workflow }}-${{ matrix.image }} @@ -134,8 +136,10 @@ jobs: # needs to be called after the package installation since # - it doesn't call "apt-get update" # - it doesn't support centos + # + # needs to be to fixated on 1.2.11 so it works with older images - see https://github.com/hendrikmuhs/ccache-action/issues/178 - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 + uses: hendrikmuhs/ccache-action@v1.2.11 if: matrix.image != 'ubuntu:14.04' # no support for --set-config with: key: ${{ github.workflow }}-${{ matrix.image }} diff --git a/.github/workflows/cppcheck-premium.yml b/.github/workflows/cppcheck-premium.yml index 2f9863d5e44..c19e557aee2 100644 --- a/.github/workflows/cppcheck-premium.yml +++ b/.github/workflows/cppcheck-premium.yml @@ -19,22 +19,23 @@ jobs: runs-on: ubuntu-22.04 # run on the latest image only env: - PREMIUM_VERSION: devdrop-20231105 + PREMIUM_VERSION: 23.12.0 steps: - uses: actions/checkout@v3 - name: Download cppcheckpremium run: | - wget https://files.cppchecksolutions.com/cppcheckpremium-${{ env.PREMIUM_VERSION }}-amd64.tar.gz + wget https://files.cppchecksolutions.com/${{ env.PREMIUM_VERSION }}/ubuntu-22.04/cppcheckpremium-${{ env.PREMIUM_VERSION }}-amd64.tar.gz + #wget https://files.cppchecksolutions.com/cppcheckpremium-${{ env.PREMIUM_VERSION }}-amd64.tar.gz tar xzf cppcheckpremium-${{ env.PREMIUM_VERSION }}-amd64.tar.gz - name: Generate a license file run: | echo cppcheck > cppcheck.lic - echo 231231 >> cppcheck.lic + echo 241231 >> cppcheck.lic echo 80000 >> cppcheck.lic - echo 57e08c39523ab54d >> cppcheck.lic + echo 53b72a908d7aeeee >> cppcheck.lic echo path:lib >> cppcheck.lic - name: Check diff --git a/Makefile b/Makefile index 92608b760a0..a73ade8692a 100644 --- a/Makefile +++ b/Makefile @@ -137,7 +137,7 @@ ifeq (clang++, $(findstring clang++,$(CXX))) CPPCHK_GLIBCXX_DEBUG= endif ifndef CXXFLAGS - CXXFLAGS=-pedantic -Wall -Wextra -Wcast-qual -Wfloat-equal -Wmissing-declarations -Wmissing-format-attribute -Wno-long-long -Wpacked -Wredundant-decls -Wundef -Wno-shadow -Wno-missing-field-initializers -Wno-missing-braces -Wno-sign-compare -Wno-multichar -Woverloaded-virtual $(CPPCHK_GLIBCXX_DEBUG) -g + CXXFLAGS=-std=c++0x -O2 -DNDEBUG -Wall -Wno-sign-compare -Wno-multichar endif ifeq (g++, $(findstring g++,$(CXX))) @@ -365,7 +365,7 @@ dmake: tools/dmake.o cli/filelister.o $(libcppdir)/pathmatch.o $(libcppdir)/path $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) run-dmake: dmake - ./dmake + ./dmake --release clean: rm -f build/*.cpp build/*.o lib/*.o cli/*.o test/*.o tools/*.o externals/*/*.o testrunner dmake cppcheck cppcheck.exe cppcheck.1 diff --git a/addons/misra.py b/addons/misra.py index 680c8c1998f..2208d9dc30e 100755 --- a/addons/misra.py +++ b/addons/misra.py @@ -4291,11 +4291,6 @@ def reportError(self, location, num1, num2): errmsg = 'misra violation (use --rule-texts= to get proper output)' else: errmsg = 'misra violation (rule-texts-file not found: ' + self.ruleText_filename + ')' - if self.path_premium_addon: - for line in cppcheckdata.cmd_output([self.path_premium_addon, '--cli', '--get-rule-text=' + errorId]).split('\n'): - if len(line) > 1 and not line.startswith('{'): - errmsg = line.strip() - break else: errmsg = 'misra violation %s with no text in the supplied rule-texts-file' % (ruleNum) diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 82ef08a4179..8a084371d7d 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -889,12 +889,38 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a // Special Cppcheck Premium options else if (std::strncmp(argv[i], "--premium=", 10) == 0 && isCppcheckPremium()) { + const std::set valid{ + "autosar", + "cert-c-2016", + "cert-c++-2016", + "cert-cpp-2016", + "misra-c-2012", + "misra-c-2023", + "misra-c++-2008", + "misra-cpp-2008", + "misra-c++-2023", + "misra-cpp-2023", + "bughunting", + "safety"}; + + if (std::strcmp(argv[i], "--premium=safety") == 0) + mSettings.safety = true; if (!mSettings.premiumArgs.empty()) mSettings.premiumArgs += " "; const std::string p(argv[i] + 10); + if (!valid.count(p) && !startsWith(p, "cert-c-int-precision=")) { + mLogger.printError("invalid --premium option '" + p + "'."); + return Result::Fail; + } mSettings.premiumArgs += "--" + p; if (p == "misra-c-2012" || p == "misra-c-2023") mSettings.addons.emplace("misra"); + if (startsWith(p, "autosar") || startsWith(p, "cert") || startsWith(p, "misra")) { + // All checkers related to the coding standard should be enabled. The coding standards + // do not all undefined behavior or portability issues. + mSettings.addEnabled("warning"); + mSettings.addEnabled("portability"); + } } // --project @@ -1513,10 +1539,11 @@ void CmdLineParser::printHelp() const " * cert-c++-2016 Cert C++ 2016 checking\n" " * misra-c-2012 Misra C 2012\n" " * misra-c-2023 Misra C 2023\n" - " * misra-c++-2008 Misra C++ 2008 (partial)\n" + " * misra-c++-2008 Misra C++ 2008\n" " Other:\n" " * bughunting Soundy analysis\n" - " * cert-c-int-precision=BITS Integer precision to use in Cert C analysis.\n"; + " * cert-c-int-precision=BITS Integer precision to use in Cert C analysis.\n" + " * safety Safe mode\n"; } oss << diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 0340d7277e0..9735fe7e1f9 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -193,6 +193,8 @@ int CppCheckExecutor::check(int argc, const char* const argv[]) mFiles = parser.getFiles(); mFileSettings = parser.getFileSettings(); + settings.setMisraRuleTexts(executeCommand); + mStdLogger = new StdLogger(settings); CppCheck cppCheck(*mStdLogger, true, executeCommand); diff --git a/cli/main.cpp b/cli/main.cpp index 7e076dfbcea..4e07cccb791 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -20,7 +20,7 @@ /** * * @mainpage Cppcheck - * @version 2.12.99 + * @version 2.13.2 * * @section overview_sec Overview * Cppcheck is a simple tool for static analysis of C/C++ code. diff --git a/cmake/versions.cmake b/cmake/versions.cmake index cf2020d3fea..11a6ec86d38 100644 --- a/cmake/versions.cmake +++ b/cmake/versions.cmake @@ -1,6 +1,6 @@ # Version for libraries CPP # Version string must have 3 "parts". https://sourceforge.net/p/cppcheck/discussion/development/thread/e57efb2b62/ -SET(VERSION "2.12.99") +SET(VERSION "2.13.4") STRING(REGEX MATCHALL "[0-9]+" VERSION_PARTS "${VERSION}") LIST(GET VERSION_PARTS 0 VERSION_MAJOR) LIST(GET VERSION_PARTS 1 VERSION_MINOR) diff --git a/cppcheckpremium-suppressions b/cppcheckpremium-suppressions index 8ca95c7ec9c..2c7b1c1ea6b 100644 --- a/cppcheckpremium-suppressions +++ b/cppcheckpremium-suppressions @@ -42,6 +42,9 @@ premium-misra-cpp-2008-0-1-12 # we sometimes don't care about return value from functions premium-misra-cpp-2008-0-1-7 +# we allow C++11 +premium-misra-cpp-2008-1-0-1 + # TODO: can we prevent commented out code? premium-misra-cpp-2008-2-7-2 premium-misra-cpp-2008-2-7-3 @@ -52,6 +55,9 @@ premium-misra-cpp-2008-2-10-1 # objects of a class often has the lowercase name of the class. premium-misra-cpp-2008-2-10-4 +# we have constants that don't have U suffix +premium-misra-cpp-2008-2-13-3 + # flag |= .. premium-misra-cpp-2008-4-5-1 @@ -76,6 +82,9 @@ premium-misra-cpp-2008-5-0-11 # conversion of char-to-int is intentional sometimes premium-misra-cpp-2008-5-0-12 +# pointer to bool conversion in condition +premium-misra-cpp-2008-5-0-13 + # pointer-to-bool conversion is common premium-misra-cpp-2008-5-0-14 @@ -106,9 +115,30 @@ premium-misra-cpp-2008-5-2-12 # we write !pointer by intention premium-misra-cpp-2008-5-3-1 +# we have side effects in && || RHS by intention +premium-misra-cpp-2008-5-14-1 + +# comma operator: we often declare many variables in the same line +premium-misra-cpp-2008-5-18-1 + +# we have quite many assignments in subexpressions. for instance in expression `tok2 = tok2->next()` it's clear a equality is not intended. +premium-misra-cpp-2008-6-2-1 + # for (;;) premium-misra-cpp-2008-6-2-3 +# we don't enforce {} below for/while +premium-misra-cpp-2008-6-3-1 + +# we don't enforce {} below if/else +premium-misra-cpp-2008-6-4-1 + +# we do not enforce final "else" +premium-misra-cpp-2008-6-4-2 + +# we have switch with return +premium-misra-cpp-2008-6-4-5 + # it's not a bug to not put default at the end of a switch body premium-misra-cpp-2008-6-4-6 @@ -131,6 +161,9 @@ premium-misra-cpp-2008-7-3-1 # intentional: return reference from method to non-const reference parameter premium-misra-cpp-2008-7-5-3 +# we have recursion by intention +premium-misra-cpp-2008-7-5-4 + # intentional declaration of multiple variables premium-misra-cpp-2008-8-0-1 @@ -143,15 +176,24 @@ premium-misra-cpp-2008-8-5-3 # TODO Fix these premium-misra-cpp-2008-9-3-1 +# methods that return non-const handles to members +premium-misra-cpp-2008-9-3-2 + # we use unions by intention sometimes premium-misra-cpp-2008-9-5-1 # overridden methods is safe premium-misra-cpp-2008-10-3-1 +# in modern c++ it's prefered to use override/final +premium-misra-cpp-2008-10-3-2 + # some classes have public members by intention premium-misra-cpp-2008-11-0-1 +# clang-tidy warns if there are redundant base class initialization [readability-redundant-member-init] +premium-misra-cpp-2008-12-1-2 + # rule should not apply to deleted copy assignment operator premium-misra-cpp-2008-12-8-2 @@ -161,8 +203,13 @@ premium-misra-cpp-2008-14-6-2 # function specializations: TODO check if we should refactor premium-misra-cpp-2008-14-8-2 +# we throw/catch token pointer in one case by intention +premium-misra-cpp-2008-15-0-2 +premium-misra-cpp-2008-15-3-5 + # we use preprocessor when it makes sense premium-misra-cpp-2008-16-0-1 +premium-misra-cpp-2008-16-0-7 premium-misra-cpp-2008-16-2-1 premium-misra-cpp-2008-16-2-2 premium-misra-cpp-2008-16-3-2 diff --git a/createrelease b/createrelease index 96f09cb6638..c41e2c440bf 100755 --- a/createrelease +++ b/createrelease @@ -5,6 +5,10 @@ # Create release candidate # ======================== # +# check every isPremiumEnabled call: +# - every id should be in --errorlist +# - premiumaddon: check coverage.py +# # Windows installer: # - ensure latest build was successful # - ensure cfg files etc are included (win_installer/cppcheck.wxs) diff --git a/externals/simplecpp/simplecpp.cpp b/externals/simplecpp/simplecpp.cpp index 881b7c7f6fc..199100c779b 100644 --- a/externals/simplecpp/simplecpp.cpp +++ b/externals/simplecpp/simplecpp.cpp @@ -393,12 +393,15 @@ class StdIStream : public simplecpp::TokenList::Stream { class FileStream : public simplecpp::TokenList::Stream { public: // cppcheck-suppress uninitDerivedMemberVar - we call Stream::init() to initialize the private members - EXPLICIT FileStream(const std::string &filename) + EXPLICIT FileStream(const std::string &filename, std::vector &files) : file(fopen(filename.c_str(), "rb")) , lastCh(0) , lastStatus(0) { - assert(file != nullptr); + if (!file) { + files.push_back(filename); + throw simplecpp::Output(files, simplecpp::Output::FILE_NOT_FOUND, "File is missing: " + filename); + } init(); } @@ -455,8 +458,15 @@ simplecpp::TokenList::TokenList(std::istream &istr, std::vector &fi simplecpp::TokenList::TokenList(const std::string &filename, std::vector &filenames, OutputList *outputList) : frontToken(nullptr), backToken(nullptr), files(filenames) { - FileStream stream(filename); - readfile(stream,filename,outputList); + try + { + FileStream stream(filename, filenames); + readfile(stream,filename,outputList); + } + catch(const simplecpp::Output & e) // TODO handle extra type of errors + { + outputList->push_back(e); + } } simplecpp::TokenList::TokenList(const TokenList &other) : frontToken(nullptr), backToken(nullptr), files(other.files) diff --git a/externals/simplecpp/simplecpp.h b/externals/simplecpp/simplecpp.h index 55a78b451c9..cd8b2dc8ab2 100644 --- a/externals/simplecpp/simplecpp.h +++ b/externals/simplecpp/simplecpp.h @@ -193,8 +193,10 @@ namespace simplecpp { SYNTAX_ERROR, PORTABILITY_BACKSLASH, UNHANDLED_CHAR_ERROR, - EXPLICIT_INCLUDE_NOT_FOUND + EXPLICIT_INCLUDE_NOT_FOUND, + FILE_NOT_FOUND } type; + explicit Output(const std::vector& files, Type type, const std::string& msg) : type(type), location(files), msg(msg) {} Location location; std::string msg; }; diff --git a/gui/checkthread.cpp b/gui/checkthread.cpp index e7d682ba0ef..e3667b52d8f 100644 --- a/gui/checkthread.cpp +++ b/gui/checkthread.cpp @@ -57,7 +57,7 @@ #endif // NOLINTNEXTLINE(performance-unnecessary-value-param) - used as callback so we need to preserve the signature -static int executeCommand(std::string exe, std::vector args, std::string redirect, std::string &output) // cppcheck-suppress passedByValueCallback +int CheckThread::executeCommand(std::string exe, std::vector args, std::string redirect, std::string &output) // cppcheck-suppress passedByValue { output.clear(); diff --git a/gui/checkthread.h b/gui/checkthread.h index 8dd3f8a80ce..f12089d330d 100644 --- a/gui/checkthread.h +++ b/gui/checkthread.h @@ -92,6 +92,8 @@ class CheckThread : public QThread { */ static QString clangTidyCmd(); + static int executeCommand(std::string exe, std::vector args, std::string redirect, std::string &output); + signals: /** diff --git a/gui/compliancereportdialog.cpp b/gui/compliancereportdialog.cpp index adcb25b4d6a..90d35f14cfa 100644 --- a/gui/compliancereportdialog.cpp +++ b/gui/compliancereportdialog.cpp @@ -96,17 +96,13 @@ ComplianceReportDialog::ComplianceReportDialog(ProjectFile* projectFile, QString mUI->mEditProjectName->setText(projectFile->getProjectName()); connect(mUI->buttonBox, &QDialogButtonBox::clicked, this, &ComplianceReportDialog::buttonClicked); mUI->mCodingStandard->clear(); - if (projectFile->getCodingStandards().contains("misra-c-2023")) - mUI->mCodingStandard->addItem("Misra C 2023"); - else if (projectFile->getAddons().contains("misra")) + if (!projectFile->getCodingStandards().contains("misra-c-2023") && projectFile->getAddons().contains("misra")) mUI->mCodingStandard->addItem("Misra C 2012"); - if (projectFile->getCodingStandards().contains("misra-c++-2008")) - mUI->mCodingStandard->addItem("Misra C++ 2008"); - if (projectFile->getCodingStandards().contains("cert-c-2016")) - mUI->mCodingStandard->addItem("Cert C"); - if (projectFile->getCodingStandards().contains("cert-c++-2016")) - mUI->mCodingStandard->addItem("Cert C++"); - mUI->mCodingStandard->addItems(projectFile->getCodingStandards()); + for (QString std: projectFile->getCodingStandards()) { + std[0] = std[0].toUpper(); + std = std.replace("-", " ").replace(" c ", " C ").replace(" cpp ", " C++ ").replace(" c++ ", " C++ "); + mUI->mCodingStandard->addItem(std); + } } ComplianceReportDialog::~ComplianceReportDialog() diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index b454ee39585..9f6e9d510c5 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -22,6 +22,7 @@ #include "applicationlist.h" #include "aboutdialog.h" #include "analyzerinfo.h" +#include "checkthread.h" #include "common.h" #include "cppcheck.h" #include "errortypes.h" @@ -486,6 +487,11 @@ void MainWindow::saveSettings() const void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLibrary, const bool checkConfiguration) { + QPair checkSettingsPair = getCppcheckSettings(); + if (!checkSettingsPair.first) + return; + Settings& checkSettings = checkSettingsPair.second; + clearResults(); mIsLogfileLoaded = false; @@ -522,7 +528,6 @@ void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLibrary, cons checkLockDownUI(); // lock UI while checking mUI->mResults->setCheckDirectory(checkPath); - Settings checkSettings = getCppcheckSettings(); checkSettings.force = false; checkSettings.checkLibrary = checkLibrary; checkSettings.checkConfiguration = checkConfiguration; @@ -550,9 +555,14 @@ void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLibrary, cons void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLibrary, const bool checkConfiguration) { - if (files.isEmpty()) { + if (files.isEmpty()) return; - } + + QPair checkSettingsPair = getCppcheckSettings(); + if (!checkSettingsPair.first) + return; + Settings& checkSettings = checkSettingsPair.second; + clearResults(); mIsLogfileLoaded = false; @@ -591,7 +601,6 @@ void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLibrar checkLockDownUI(); // lock UI while checking mUI->mResults->setCheckDirectory(checkPath); - Settings checkSettings = getCppcheckSettings(); checkSettings.checkLibrary = checkLibrary; checkSettings.checkConfiguration = checkConfiguration; @@ -614,6 +623,11 @@ void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLibrar void MainWindow::analyzeCode(const QString& code, const QString& filename) { + const QPair& checkSettingsPair = getCppcheckSettings(); + if (!checkSettingsPair.first) + return; + const Settings& checkSettings = checkSettingsPair.second; + // Initialize dummy ThreadResult as ErrorLogger ThreadResult result; result.setFiles(QStringList(filename)); @@ -628,7 +642,7 @@ void MainWindow::analyzeCode(const QString& code, const QString& filename) // Create CppCheck instance CppCheck cppcheck(result, true, nullptr); - cppcheck.settings() = getCppcheckSettings(); + cppcheck.settings() = checkSettings; // Check checkLockDownUI(); @@ -905,13 +919,12 @@ bool MainWindow::tryLoadLibrary(Library *library, const QString& filename) return true; } -void MainWindow::loadAddon(Settings &settings, const QString &filesDir, const QString &pythonCmd, const QString& addon) +QString MainWindow::loadAddon(Settings &settings, const QString &filesDir, const QString &pythonCmd, const QString& addon) { - QString addonFilePath = ProjectFile::getAddonFilePath(filesDir, addon); - if (addonFilePath.isEmpty()) - return; // TODO: report an error + const QString addonFilePath = fromNativePath(ProjectFile::getAddonFilePath(filesDir, addon)); - addonFilePath.replace(QChar('\\'), QChar('/')); + if (addonFilePath.isEmpty()) + return tr("File not found: '%1'").arg(addon); picojson::object obj; obj["script"] = picojson::value(addonFilePath.toStdString()); @@ -929,42 +942,54 @@ void MainWindow::loadAddon(Settings &settings, const QString &filesDir, const QS obj["args"] = picojson::value(arg.toStdString()); } } - picojson::value json; - json.set(std::move(obj)); - std::string json_str = json.serialize(); + + const std::string& json_str = picojson::value(obj).serialize(); AddonInfo addonInfo; - addonInfo.getAddonInfo(json_str, settings.exename); // TODO: handle error + const std::string errmsg = addonInfo.getAddonInfo(json_str, settings.exename); + if (!errmsg.empty()) + return tr("Failed to load/setup addon %1: %2").arg(addon, QString::fromStdString(errmsg)); settings.addonInfos.emplace_back(std::move(addonInfo)); - settings.addons.emplace(std::move(json_str)); + settings.addons.emplace(json_str); + + return ""; } -Settings MainWindow::getCppcheckSettings() +QPair MainWindow::getCppcheckSettings() { saveSettings(); // Save settings + Settings::terminate(true); Settings result; result.exename = QCoreApplication::applicationFilePath().toStdString(); const bool std = tryLoadLibrary(&result.library, "std.cfg"); - if (!std) - QMessageBox::critical(this, tr("Error"), tr("Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir= at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured.").arg("std.cfg")); + if (!std) { + QMessageBox::critical(this, tr("Error"), tr("Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir= at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured.\n\nAnalysis is aborted.").arg("std.cfg")); + return {false, {}}; + } const QString filesDir(getDataDir()); const QString pythonCmd = fromNativePath(mSettings->value(SETTINGS_PYTHON_PATH).toString()); { const QString cfgErr = QString::fromStdString(result.loadCppcheckCfg()); - if (!cfgErr.isEmpty()) - QMessageBox::critical(this, tr("Error"), tr("Failed to load %1 - %2").arg("cppcheck.cfg").arg(cfgErr)); + if (!cfgErr.isEmpty()) { + QMessageBox::critical(this, tr("Error"), tr("Failed to load %1 - %2\n\nAnalysis is aborted.").arg("cppcheck.cfg").arg(cfgErr)); + return {false, {}}; + } const auto cfgAddons = result.addons; result.addons.clear(); for (const std::string& addon : cfgAddons) { // TODO: support addons which are a script and not a file - loadAddon(result, filesDir, pythonCmd, QString::fromStdString(addon)); + const QString addonError = loadAddon(result, filesDir, pythonCmd, QString::fromStdString(addon)); + if (!addonError.isEmpty()) { + QMessageBox::critical(this, tr("Error"), tr("%1\n\nAnalysis is aborted.").arg(addonError)); + return {false, {}}; + } } } @@ -1045,7 +1070,11 @@ Settings MainWindow::getCppcheckSettings() result.checkUnknownFunctionReturn.insert(s.toStdString()); for (const QString& addon : mProjectFile->getAddons()) { - loadAddon(result, filesDir, pythonCmd, addon); + const QString addonError = loadAddon(result, filesDir, pythonCmd, addon); + if (!addonError.isEmpty()) { + QMessageBox::critical(this, tr("Error"), tr("%1\n\nAnalysis is aborted.").arg(addonError)); + return {false, {}}; + } } if (isCppcheckPremium()) { @@ -1059,6 +1088,7 @@ Settings MainWindow::getCppcheckSettings() if (!premiumArgs.contains("misra") && mProjectFile->getAddons().contains("misra")) premiumArgs += " --misra-c-2012"; result.premiumArgs = premiumArgs.mid(1).toStdString(); + result.setMisraRuleTexts(CheckThread::executeCommand); } } @@ -1099,7 +1129,7 @@ Settings MainWindow::getCppcheckSettings() Settings::terminate(false); - return result; + return {true, std::move(result)}; } void MainWindow::analysisDone() @@ -1223,6 +1253,11 @@ void MainWindow::reAnalyzeSelected(const QStringList& files) if (mThread->isChecking()) return; + const QPair checkSettingsPair = getCppcheckSettings(); + if (!checkSettingsPair.first) + return; + const Settings& checkSettings = checkSettingsPair.second; + // Clear details, statistics and progress mUI->mResults->clear(false); for (int i = 0; i < files.size(); ++i) @@ -1242,7 +1277,6 @@ void MainWindow::reAnalyzeSelected(const QStringList& files) // considered in "Modified Files Check" performed after "Selected Files Check" // TODO: Should we store per file CheckStartTime? QDateTime saveCheckStartTime = mThread->getCheckStartTime(); - const Settings& checkSettings = getCppcheckSettings(); mThread->check(checkSettings); mUI->mResults->setCheckSettings(checkSettings); mThread->setCheckStartTime(saveCheckStartTime); @@ -1254,6 +1288,11 @@ void MainWindow::reAnalyze(bool all) if (files.empty()) return; + const QPair& checkSettingsPair = getCppcheckSettings(); + if (!checkSettingsPair.first) + return; + const Settings& checkSettings = checkSettingsPair.second; + // Clear details, statistics and progress mUI->mResults->clear(all); @@ -1268,7 +1307,6 @@ void MainWindow::reAnalyze(bool all) qDebug() << "Rechecking project file" << mProjectFile->getFilename(); mThread->setCheckFiles(all); - const Settings& checkSettings = getCppcheckSettings(); mThread->check(checkSettings); mUI->mResults->setCheckSettings(checkSettings); } @@ -1359,7 +1397,7 @@ void MainWindow::enableCheckButtons(bool enable) mUI->mActionAnalyzeDirectory->setEnabled(enable); if (isCppcheckPremium()) { - mUI->mActionComplianceReport->setEnabled(enable && mProjectFile && mProjectFile->getAddons().contains("misra")); + mUI->mActionComplianceReport->setEnabled(enable && mProjectFile && (mProjectFile->getAddons().contains("misra") || !mProjectFile->getCodingStandards().empty())); } } diff --git a/gui/mainwindow.h b/gui/mainwindow.h index 4b6b20f9ad3..b0f059218cf 100644 --- a/gui/mainwindow.h +++ b/gui/mainwindow.h @@ -315,7 +315,7 @@ private slots: * * @return Default cppcheck settings */ - Settings getCppcheckSettings(); + QPair getCppcheckSettings(); /** @brief Load program settings */ void loadSettings(); @@ -401,7 +401,7 @@ private slots: */ bool tryLoadLibrary(Library *library, const QString& filename); - void loadAddon(Settings &settings, const QString &filesDir, const QString &pythonCmd, const QString& addon); + QString loadAddon(Settings &settings, const QString &filesDir, const QString &pythonCmd, const QString& addon); /** * @brief Update project MRU items in File-menu. diff --git a/gui/projectfile.cpp b/gui/projectfile.cpp index f24f6eece93..393063bb49d 100644 --- a/gui/projectfile.cpp +++ b/gui/projectfile.cpp @@ -1115,6 +1115,9 @@ void ProjectFile::SafeChecks::saveToXml(QXmlStreamWriter &xmlWriter) const QString ProjectFile::getAddonFilePath(QString filesDir, const QString &addon) { + if (QFile(addon).exists()) + return addon; + if (!filesDir.endsWith("/")) filesDir += "/"; diff --git a/gui/test/projectfile/testprojectfile.cpp b/gui/test/projectfile/testprojectfile.cpp index 6e5e73b0f06..505a6e8937c 100644 --- a/gui/test/projectfile/testprojectfile.cpp +++ b/gui/test/projectfile/testprojectfile.cpp @@ -28,6 +28,7 @@ #include #include +#include #include // Mock... @@ -116,4 +117,23 @@ void TestProjectFile::loadSimpleNoroot() const QCOMPARE(defines[0], QString("FOO")); } +void TestProjectFile::getAddonFilePath() const +{ + QTemporaryDir tempdir; + QVERIFY(tempdir.isValid()); + const QString filepath(tempdir.path() + "/addon.py"); + + QFile file(filepath); + QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Text)); + file.close(); + + // Relative path to addon + QCOMPARE(ProjectFile::getAddonFilePath(tempdir.path(), "addon"), filepath); + QCOMPARE(ProjectFile::getAddonFilePath(tempdir.path(), "not exist"), QString()); + + // Absolute path to addon + QCOMPARE(ProjectFile::getAddonFilePath("/not/exist", filepath), filepath); + QCOMPARE(ProjectFile::getAddonFilePath(tempdir.path(), filepath), filepath); +} + QTEST_MAIN(TestProjectFile) diff --git a/gui/test/projectfile/testprojectfile.h b/gui/test/projectfile/testprojectfile.h index b0bc7d96969..47ed517f412 100644 --- a/gui/test/projectfile/testprojectfile.h +++ b/gui/test/projectfile/testprojectfile.h @@ -27,4 +27,6 @@ private slots: void loadSimple() const; void loadSimpleWithIgnore() const; void loadSimpleNoroot() const; + + void getAddonFilePath() const; }; diff --git a/lib/addoninfo.cpp b/lib/addoninfo.cpp index cfe720b81e7..66eabdccd4f 100644 --- a/lib/addoninfo.cpp +++ b/lib/addoninfo.cpp @@ -80,11 +80,18 @@ static std::string parseAddonInfo(AddonInfo& addoninfo, const picojson::value &j addoninfo.python = ""; } - if (obj.count("executable")) { - if (!obj["executable"].is()) - return "Loading " + fileName + " failed. executable must be a string."; - addoninfo.executable = getFullPath(obj["executable"].get(), fileName); - return ""; + { + const auto it = obj.find("executable"); + if (it != obj.cend()) { + const auto& val = it->second; + if (!val.is()) + return "Loading " + fileName + " failed. 'executable' must be a string."; + const std::string e = val.get(); + addoninfo.executable = getFullPath(e, fileName); + if (addoninfo.executable.empty()) + addoninfo.executable = e; + return ""; // <- do not load both "executable" and "script". + } } return addoninfo.getAddonInfo(obj["script"].get(), exename); @@ -126,6 +133,11 @@ std::string AddonInfo::getAddonInfo(const std::string &fileName, const std::stri std::ifstream fin(fileName); if (!fin.is_open()) return "Failed to open " + fileName; + if (name.empty()) { + name = Path::fromNativeSeparators(fileName); + if (name.find('/') != std::string::npos) + name = name.substr(name.rfind('/') + 1); + } picojson::value json; fin >> json; return parseAddonInfo(*this, json, fileName, exename); diff --git a/lib/checkautovariables.cpp b/lib/checkautovariables.cpp index 895ee5387d1..c19f7ad9bac 100644 --- a/lib/checkautovariables.cpp +++ b/lib/checkautovariables.cpp @@ -210,7 +210,7 @@ void CheckAutoVariables::assignFunctionArg() { const bool printStyle = mSettings->severity.isEnabled(Severity::style); const bool printWarning = mSettings->severity.isEnabled(Severity::warning); - if (!printStyle && !printWarning) + if (!printStyle && !printWarning && !mSettings->isPremiumEnabled("uselessAssignmentPtrArg")) return; logChecker("CheckAutoVariables::assignFunctionArg"); // style,warning diff --git a/lib/checkbool.cpp b/lib/checkbool.cpp index 4de26ea2801..bf2500972fb 100644 --- a/lib/checkbool.cpp +++ b/lib/checkbool.cpp @@ -50,7 +50,7 @@ static bool isBool(const Variable* var) //--------------------------------------------------------------------------- void CheckBool::checkIncrementBoolean() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("incrementboolean")) return; logChecker("CheckBool::checkIncrementBoolean"); // style diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 9d3fa47fc0e..cc14d8c6477 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -127,7 +127,7 @@ void CheckClass::constructors() { const bool printStyle = mSettings->severity.isEnabled(Severity::style); const bool printWarnings = mSettings->severity.isEnabled(Severity::warning); - if (!printStyle && !printWarnings) + if (!printStyle && !printWarnings && !mSettings->isPremiumEnabled("uninitMemberVar")) return; logChecker("CheckClass::checkConstructors"); // style,warning @@ -336,7 +336,7 @@ void CheckClass::constructors() void CheckClass::checkExplicitConstructors() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("noExplicitConstructor")) return; logChecker("CheckClass::checkExplicitConstructors"); // style @@ -1275,7 +1275,7 @@ static bool checkFunctionUsage(const Function *privfunc, const Scope* scope) void CheckClass::privateFunctions() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedPrivateFunction")) return; logChecker("CheckClass::privateFunctions"); // style @@ -1564,7 +1564,7 @@ void CheckClass::memsetErrorFloat(const Token *tok, const std::string &type) void CheckClass::operatorEqRetRefThis() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("operatorEqRetRefThis")) return; logChecker("CheckClass::operatorEqRetRefThis"); // style @@ -2090,7 +2090,9 @@ void CheckClass::checkConst() if (!mSettings->certainty.isEnabled(Certainty::inconclusive)) return; - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && + !mSettings->isPremiumEnabled("functionConst") && + !mSettings->isPremiumEnabled("functionStatic")) return; logChecker("CheckClass::checkConst"); // style,inconclusive @@ -2638,7 +2640,7 @@ namespace { // avoid one-definition-rule violation void CheckClass::initializerListOrder() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("initializerList")) return; // This check is not inconclusive. However it only determines if the initialization @@ -3112,7 +3114,7 @@ void CheckClass::copyCtorAndEqOperatorError(const Token *tok, const std::string void CheckClass::checkOverride() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("missingOverride")) return; if (mSettings->standards.cpp < Standards::CPP11) return; @@ -3212,7 +3214,7 @@ static bool compareTokenRanges(const Token* start1, const Token* end1, const Tok void CheckClass::checkUselessOverride() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("uselessOverride")) return; logChecker("CheckClass::checkUselessOverride"); // style diff --git a/lib/checkcondition.cpp b/lib/checkcondition.cpp index 8e5e3f134ba..38d20ed72a4 100644 --- a/lib/checkcondition.cpp +++ b/lib/checkcondition.cpp @@ -87,7 +87,7 @@ bool CheckCondition::isAliased(const std::set &vars) const void CheckCondition::assignIf() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("assignIf")) return; logChecker("CheckCondition::assignIf"); // style @@ -306,7 +306,7 @@ static bool isOperandExpanded(const Token *tok) void CheckCondition::checkBadBitmaskCheck() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("badBitmaskCheck")) return; logChecker("CheckCondition::checkBadBitmaskCheck"); // style @@ -354,7 +354,7 @@ void CheckCondition::badBitmaskCheckError(const Token *tok, bool isNoOp) void CheckCondition::comparison() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("comparisonError")) return; logChecker("CheckCondition::comparison"); // style @@ -474,7 +474,7 @@ bool CheckCondition::isOverlappingCond(const Token * const cond1, const Token * void CheckCondition::duplicateCondition() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("duplicateCondition")) return; logChecker("CheckCondition::duplicateCondition"); // style @@ -525,7 +525,7 @@ void CheckCondition::duplicateConditionError(const Token *tok1, const Token *tok void CheckCondition::multiCondition() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("multiCondition")) return; logChecker("CheckCondition::multiCondition"); // style @@ -1125,7 +1125,7 @@ void CheckCondition::checkIncorrectLogicOperator() { const bool printStyle = mSettings->severity.isEnabled(Severity::style); const bool printWarning = mSettings->severity.isEnabled(Severity::warning); - if (!printWarning && !printStyle) + if (!printWarning && !printStyle && !mSettings->isPremiumEnabled("incorrectLogicOperator")) return; const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive); @@ -1417,7 +1417,7 @@ static int countPar(const Token *tok1, const Token *tok2) //--------------------------------------------------------------------------- void CheckCondition::clarifyCondition() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("clarifyCondition")) return; const bool isC = mTokenizer->isC(); @@ -1483,7 +1483,9 @@ void CheckCondition::clarifyConditionError(const Token *tok, bool assign, bool b void CheckCondition::alwaysTrueFalse() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && + !mSettings->isPremiumEnabled("alwaysTrue") && + !mSettings->isPremiumEnabled("alwaysFalse")) return; logChecker("CheckCondition::alwaysTrueFalse"); // style @@ -1785,7 +1787,7 @@ void CheckCondition::pointerAdditionResultNotNullError(const Token *tok, const T void CheckCondition::checkDuplicateConditionalAssign() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("duplicateConditionalAssign")) return; logChecker("CheckCondition::checkDuplicateConditionalAssign"); // style @@ -1864,7 +1866,7 @@ void CheckCondition::duplicateConditionalAssignError(const Token *condTok, const void CheckCondition::checkAssignmentInCondition() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("assignmentInCondition")) return; logChecker("CheckCondition::checkAssignmentInCondition"); // style @@ -1911,7 +1913,7 @@ void CheckCondition::assignmentInCondition(const Token *eq) void CheckCondition::checkCompareValueOutOfTypeRange() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("compareValueOutOfTypeRange")) return; if (mSettings->platform.type == Platform::Type::Native || diff --git a/lib/checkers.cpp b/lib/checkers.cpp index da054e635e7..f668665cfdf 100644 --- a/lib/checkers.cpp +++ b/lib/checkers.cpp @@ -64,6 +64,7 @@ namespace checkers { {"CheckStl::checkDereferenceInvalidIterator2",""}, {"CheckStl::useStlAlgorithm","style"}, {"CheckStl::knownEmptyContainer","style"}, + {"CheckStl::eraseIteratorOutOfBounds",""}, {"CheckStl::checkMutexes","warning"}, {"CheckBoost::checkBoostForeachModification",""}, {"CheckNullPointer::nullPointer",""}, @@ -291,7 +292,7 @@ namespace checkers { {"Cert C++: ERR51-CPP","style"}, {"Cert C++: ERR52-CPP","style"}, {"Cert C++: ERR53-CPP",""}, - {"Cert C++: ERR54-CPP",""}, + {"Cert C++: ERR54-CPP","style"}, {"Cert C++: ERR55-CPP",""}, {"Cert C++: ERR56-CPP",""}, {"Cert C++: ERR58-CPP",""}, @@ -324,95 +325,101 @@ namespace checkers { {"Cert C++: OOP58-CPP","style"}, {"Cert C++: STR50-CPP",""}, {"Cert C++: STR53-CPP",""}, - {"Cert C: ARR30-C","warning"}, - {"Cert C: ARR32-C","warning"}, - {"Cert C: ARR37-C","warning"}, + {"Cert C: ARR30-C",""}, + {"Cert C: ARR32-C",""}, + {"Cert C: ARR37-C",""}, {"Cert C: ARR38-C",""}, - {"Cert C: ARR39-C","warning"}, - {"Cert C: CON30-C","style"}, - {"Cert C: CON31-C","style"}, - {"Cert C: CON32-C","style"}, - {"Cert C: CON33-C","style"}, - {"Cert C: CON34-C","warning"}, - {"Cert C: CON35-C","warning"}, - {"Cert C: CON36-C","style"}, - {"Cert C: CON37-C","style"}, - {"Cert C: CON38-C","warning"}, - {"Cert C: CON39-C","warning"}, - {"Cert C: CON40-C","warning"}, - {"Cert C: CON41-C","style"}, - {"Cert C: DCL31-C","style"}, - {"Cert C: DCL36-C","style"}, - {"Cert C: DCL37-C","style"}, - {"Cert C: DCL38-C","style"}, - {"Cert C: DCL39-C","style"}, - {"Cert C: DCL40-C","style"}, - {"Cert C: DCL41-C","style"}, - {"Cert C: ENV30-C","style"}, - {"Cert C: ENV31-C","style"}, - {"Cert C: ENV32-C","style"}, - {"Cert C: ENV33-C","style"}, - {"Cert C: ENV34-C","style"}, - {"Cert C: ERR30-C","warning"}, - {"Cert C: ERR32-C","warning"}, - {"Cert C: ERR33-C","warning"}, - {"Cert C: EXP32-C","warning"}, + {"Cert C: ARR39-C",""}, + {"Cert C: CON30-C",""}, + {"Cert C: CON31-C",""}, + {"Cert C: CON32-C",""}, + {"Cert C: CON33-C",""}, + {"Cert C: CON34-C",""}, + {"Cert C: CON35-C",""}, + {"Cert C: CON36-C",""}, + {"Cert C: CON37-C",""}, + {"Cert C: CON38-C",""}, + {"Cert C: CON39-C",""}, + {"Cert C: CON40-C",""}, + {"Cert C: CON41-C",""}, + {"Cert C: DCL31-C",""}, + {"Cert C: DCL36-C",""}, + {"Cert C: DCL37-C",""}, + {"Cert C: DCL38-C",""}, + {"Cert C: DCL39-C",""}, + {"Cert C: DCL40-C",""}, + {"Cert C: DCL41-C",""}, + {"Cert C: ENV30-C",""}, + {"Cert C: ENV31-C",""}, + {"Cert C: ENV32-C",""}, + {"Cert C: ENV33-C",""}, + {"Cert C: ENV34-C",""}, + {"Cert C: ERR30-C",""}, + {"Cert C: ERR32-C",""}, + {"Cert C: ERR33-C",""}, + {"Cert C: EXP32-C",""}, {"Cert C: EXP35-C",""}, - {"Cert C: EXP36-C","style"}, - {"Cert C: EXP37-C","style"}, - {"Cert C: EXP39-C","style"}, - {"Cert C: EXP40-C","style"}, - {"Cert C: EXP42-C","style"}, - {"Cert C: EXP43-C","style"}, - {"Cert C: EXP45-C","warning"}, - {"Cert C: FIO30-C","warning"}, - {"Cert C: FIO32-C","style"}, - {"Cert C: FIO34-C","style"}, + {"Cert C: EXP36-C",""}, + {"Cert C: EXP37-C",""}, + {"Cert C: EXP39-C",""}, + {"Cert C: EXP40-C",""}, + {"Cert C: EXP42-C",""}, + {"Cert C: EXP43-C",""}, + {"Cert C: EXP45-C",""}, + {"Cert C: FIO30-C",""}, + {"Cert C: FIO32-C",""}, + {"Cert C: FIO34-C",""}, {"Cert C: FIO37-C",""}, - {"Cert C: FIO38-C","style"}, - {"Cert C: FIO40-C","style"}, - {"Cert C: FIO41-C","style"}, - {"Cert C: FIO44-C","warning"}, - {"Cert C: FIO45-C","warning"}, - {"Cert C: FLP30-C","warning"}, + {"Cert C: FIO38-C",""}, + {"Cert C: FIO40-C",""}, + {"Cert C: FIO41-C",""}, + {"Cert C: FIO44-C",""}, + {"Cert C: FIO45-C",""}, + {"Cert C: FLP30-C",""}, {"Cert C: FLP36-C","portability"}, - {"Cert C: FLP37-C","style"}, - {"Cert C: INT30-C","warning"}, - {"Cert C: INT31-C","warning"}, - {"Cert C: INT32-C","warning"}, - {"Cert C: INT33-C","warning"}, - {"Cert C: INT34-C","warning"}, - {"Cert C: INT35-C","warning"}, - {"Cert C: INT36-C","warning"}, - {"Cert C: MEM33-C","style"}, - {"Cert C: MEM35-C","warning"}, - {"Cert C: MEM36-C","warning"}, - {"Cert C: MSC30-C","style"}, - {"Cert C: MSC32-C","style"}, - {"Cert C: MSC33-C","style"}, - {"Cert C: MSC38-C","warning"}, - {"Cert C: MSC39-C","warning"}, - {"Cert C: MSC40-C","warning"}, - {"Cert C: PRE31-C","style"}, - {"Cert C: SIG30-C","style"}, - {"Cert C: SIG31-C","warning"}, - {"Cert C: SIG34-C","style"}, - {"Cert C: SIG35-C","warning"}, - {"Cert C: STR31-C","warning"}, - {"Cert C: STR32-C","warning"}, - {"Cert C: STR34-C","warning"}, - {"Cert C: STR38-C","style"}, + {"Cert C: FLP37-C",""}, + {"Cert C: INT30-C",""}, + {"Cert C: INT31-C",""}, + {"Cert C: INT32-C",""}, + {"Cert C: INT33-C",""}, + {"Cert C: INT34-C",""}, + {"Cert C: INT35-C",""}, + {"Cert C: INT36-C",""}, + {"Cert C: MEM33-C",""}, + {"Cert C: MEM35-C",""}, + {"Cert C: MEM36-C",""}, + {"Cert C: MSC30-C",""}, + {"Cert C: MSC32-C",""}, + {"Cert C: MSC33-C",""}, + {"Cert C: MSC38-C",""}, + {"Cert C: MSC39-C",""}, + {"Cert C: MSC40-C",""}, + {"Cert C: PRE31-C",""}, + {"Cert C: SIG30-C",""}, + {"Cert C: SIG31-C",""}, + {"Cert C: SIG34-C",""}, + {"Cert C: SIG35-C",""}, + {"Cert C: STR31-C",""}, + {"Cert C: STR32-C",""}, + {"Cert C: STR34-C",""}, + {"Cert C: STR38-C",""}, + {"Misra C++ 2023: 21.20.1",""}, + {"Misra C++ 2023: 21.20.2",""}, + {"Misra C++ 2023: 6.7.1",""}, {"Misra C++: M0-1-11","style"}, {"Misra C++: M0-1-12","style"}, {"Misra C++: M0-1-4","style"}, {"Misra C++: M0-1-5","style"}, {"Misra C++: M0-1-7","style"}, {"Misra C++: M0-1-8","style"}, + {"Misra C++: M0-3-2","style"}, + {"Misra C++: M1-0-1","portability"}, {"Misra C++: M10-1-1","style"}, {"Misra C++: M10-1-2","style"}, {"Misra C++: M10-1-3","style"}, {"Misra C++: M10-2-1","style"}, {"Misra C++: M10-3-1","style"}, + {"Misra C++: M10-3-2","style"}, {"Misra C++: M10-3-3","style"}, {"Misra C++: M11-0-1","style"}, {"Misra C++: M12-1-2","style"}, @@ -435,13 +442,19 @@ namespace checkers { {"Misra C++: M15-3-2","warning"}, {"Misra C++: M15-3-3",""}, {"Misra C++: M15-3-4",""}, + {"Misra C++: M15-3-6","style"}, + {"Misra C++: M15-3-7","style"}, {"Misra C++: M15-4-1","style"}, {"Misra C++: M15-5-2",""}, {"Misra C++: M16-0-1","style"}, {"Misra C++: M16-0-2","style"}, {"Misra C++: M16-0-3","style"}, {"Misra C++: M16-0-4","style"}, + {"Misra C++: M16-0-6","style"}, + {"Misra C++: M16-0-7","style"}, + {"Misra C++: M16-0-8","style"}, {"Misra C++: M16-1-1","style"}, + {"Misra C++: M16-1-2","style"}, {"Misra C++: M16-2-1","style"}, {"Misra C++: M16-2-2","style"}, {"Misra C++: M16-2-3","style"}, @@ -468,8 +481,11 @@ namespace checkers { {"Misra C++: M2-10-4","style"}, {"Misra C++: M2-10-5","style"}, {"Misra C++: M2-10-6","style"}, + {"Misra C++: M2-13-2","style"}, + {"Misra C++: M2-13-3","style"}, {"Misra C++: M2-13-4","style"}, {"Misra C++: M2-13-5","style"}, + {"Misra C++: M2-3-1","style"}, {"Misra C++: M2-7-1","style"}, {"Misra C++: M2-7-2","style"}, {"Misra C++: M2-7-3","style"}, @@ -503,7 +519,10 @@ namespace checkers { {"Misra C++: M5-0-7","style"}, {"Misra C++: M5-0-8","style"}, {"Misra C++: M5-0-9","style"}, + {"Misra C++: M5-14-1","style"}, {"Misra C++: M5-17-1","style"}, + {"Misra C++: M5-18-1","style"}, + {"Misra C++: M5-19-1","style"}, {"Misra C++: M5-2-1","style"}, {"Misra C++: M5-2-10","style"}, {"Misra C++: M5-2-11","style"}, @@ -518,8 +537,15 @@ namespace checkers { {"Misra C++: M5-3-1","style"}, {"Misra C++: M5-3-2","style"}, {"Misra C++: M5-3-3","style"}, + {"Misra C++: M6-2-1","style"}, + {"Misra C++: M6-2-2","style"}, {"Misra C++: M6-2-3","style"}, + {"Misra C++: M6-3-1","style"}, + {"Misra C++: M6-4-1","style"}, + {"Misra C++: M6-4-2","style"}, + {"Misra C++: M6-4-3","style"}, {"Misra C++: M6-4-4","style"}, + {"Misra C++: M6-4-5","style"}, {"Misra C++: M6-4-6","style"}, {"Misra C++: M6-4-7","style"}, {"Misra C++: M6-4-8","style"}, @@ -530,6 +556,7 @@ namespace checkers { {"Misra C++: M6-5-5","style"}, {"Misra C++: M6-5-6","style"}, {"Misra C++: M6-6-1","style"}, + {"Misra C++: M6-6-2","style"}, {"Misra C++: M6-6-3","style"}, {"Misra C++: M6-6-4","style"}, {"Misra C++: M6-6-5","style"}, @@ -563,14 +590,31 @@ namespace checkers { {"Misra C: 10.7","style"}, {"Misra C: 10.8","style"}, {"Misra C: 11.10","style"}, + {"Misra C: 12.3","style"}, {"Misra C: 12.6",""}, + {"Misra C: 13.1","style"}, + {"Misra C: 13.2","style"}, + {"Misra C: 13.3","style"}, + {"Misra C: 13.4","style"}, + {"Misra C: 13.5","style"}, + {"Misra C: 13.6","style"}, + {"Misra C: 15.5",""}, + {"Misra C: 16.3","style"}, {"Misra C: 17.10","style"}, {"Misra C: 17.11","style"}, {"Misra C: 17.12","style"}, + {"Misra C: 17.13",""}, + {"Misra C: 17.3",""}, {"Misra C: 17.9","style"}, {"Misra C: 18.10","style"}, + {"Misra C: 18.5","style"}, + {"Misra C: 18.8","style"}, {"Misra C: 18.9","style"}, + {"Misra C: 20.3","style"}, + {"Misra C: 21.1","style"}, {"Misra C: 21.12","style"}, + {"Misra C: 21.16","style"}, + {"Misra C: 21.2","style"}, {"Misra C: 21.22","style"}, {"Misra C: 21.23","style"}, {"Misra C: 21.24","style"}, @@ -601,6 +645,7 @@ namespace checkers { {"Misra C: 8.15","style"}, {"Misra C: 8.16","style"}, {"Misra C: 8.17","style"}, + {"Misra C: 8.3","style"}, {"Misra C: 9.6","style"}, {"Misra C: 9.7",""}, {"PremiumCheckBufferOverrun::addressOfPointerArithmetic","warning"}, diff --git a/lib/checkexceptionsafety.cpp b/lib/checkexceptionsafety.cpp index 2c404e8312e..bd217d8c545 100644 --- a/lib/checkexceptionsafety.cpp +++ b/lib/checkexceptionsafety.cpp @@ -169,7 +169,7 @@ void CheckExceptionSafety::deallocThrowError(const Token * const tok, const std: //--------------------------------------------------------------------------- void CheckExceptionSafety::checkRethrowCopy() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("rethrowcopy")) return; logChecker("CheckExceptionSafety::checkRethrowCopy"); // style @@ -213,7 +213,7 @@ void CheckExceptionSafety::rethrowCopyError(const Token * const tok, const std:: //--------------------------------------------------------------------------- void CheckExceptionSafety::checkCatchExceptionByValue() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("catchexceptionbyvalue")) return; logChecker("CheckExceptionSafety::checkCatchExceptionByValue"); // style @@ -329,7 +329,8 @@ void CheckExceptionSafety::noexceptThrowError(const Token * const tok) //-------------------------------------------------------------------------- void CheckExceptionSafety::unhandledExceptionSpecification() { - if (!mSettings->severity.isEnabled(Severity::style) || !mSettings->certainty.isEnabled(Certainty::inconclusive)) + if ((!mSettings->severity.isEnabled(Severity::style) || !mSettings->certainty.isEnabled(Certainty::inconclusive)) && + !mSettings->isPremiumEnabled("unhandledexceptionspecification")) return; logChecker("CheckExceptionSafety::unhandledExceptionSpecification"); // style,inconclusive diff --git a/lib/checkfunctions.cpp b/lib/checkfunctions.cpp index cd9b8f980d3..da7f6a734a2 100644 --- a/lib/checkfunctions.cpp +++ b/lib/checkfunctions.cpp @@ -242,7 +242,9 @@ void CheckFunctions::invalidFunctionArgStrError(const Token *tok, const std::str //--------------------------------------------------------------------------- void CheckFunctions::checkIgnoredReturnValue() { - if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::warning) && + !mSettings->severity.isEnabled(Severity::style) && + !mSettings->isPremiumEnabled("ignoredReturnValue")) return; logChecker("CheckFunctions::checkIgnoredReturnValue"); // style,warning @@ -424,7 +426,7 @@ void CheckFunctions::checkMathFunctions() const bool styleC99 = mSettings->severity.isEnabled(Severity::style) && mSettings->standards.c != Standards::C89 && mSettings->standards.cpp != Standards::CPP03; const bool printWarnings = mSettings->severity.isEnabled(Severity::warning); - if (!styleC99 && !printWarnings) + if (!styleC99 && !printWarnings && !mSettings->isPremiumEnabled("wrongmathcall")) return; logChecker("CheckFunctions::checkMathFunctions"); // style,warning,c99,c++11 diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index a3c7d4a0177..ad588558117 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -635,7 +635,7 @@ void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarnam void CheckMemoryLeakInClass::unsafeClassError(const Token *tok, const std::string &classname, const std::string &varname) { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unsafeClassCanLeak")) return; reportError(tok, Severity::style, "unsafeClassCanLeak", diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 3e324a6833d..0fb67986f37 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -154,7 +154,7 @@ void CheckOther::checkCastIntToCharAndBackError(const Token *tok, const std::str //--------------------------------------------------------------------------- void CheckOther::clarifyCalculation() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("clarifyCalculation")) return; logChecker("CheckOther::clarifyCalculation"); // style @@ -296,7 +296,10 @@ void CheckOther::suspiciousSemicolonError(const Token* tok) void CheckOther::warningOldStylePointerCast() { // Only valid on C++ code - if (!mSettings->severity.isEnabled(Severity::style) || !mTokenizer->isCPP()) + if (!mTokenizer->isCPP()) + return; + + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("cstyleCast")) return; logChecker("CheckOther::warningOldStylePointerCast"); // style,c++ @@ -402,7 +405,7 @@ void CheckOther::invalidPointerCastError(const Token* tok, const std::string& fr void CheckOther::checkRedundantAssignment() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("redundantAssignment")) return; logChecker("CheckOther::checkRedundantAssignment"); // style @@ -747,7 +750,11 @@ void CheckOther::suspiciousCaseInSwitchError(const Token* tok, const std::string //--------------------------------------------------------------------------- void CheckOther::checkUnreachableCode() { - if (!mSettings->severity.isEnabled(Severity::style)) + // misra-c-2012-2.1 + // misra-c-2023-2.1 + // misra-cpp-2008-0-1-1 + // autosar + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unreachableCode")) return; logChecker("CheckOther::checkUnreachableCode"); // style @@ -901,7 +908,7 @@ void CheckOther::checkVariableScope() if (mSettings->clang) return; - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("variableScope")) return; const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -1489,7 +1496,9 @@ static const Token* getVariableChangedStart(const Variable* p) void CheckOther::checkConstPointer() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && + !mSettings->isPremiumEnabled("constParameter") && + !mSettings->isPremiumEnabled("constPointer")) return; logChecker("CheckOther::checkConstPointer"); // style @@ -2048,7 +2057,7 @@ void CheckOther::zerodivError(const Token *tok, const ValueFlow::Value *value) void CheckOther::checkNanInArithmeticExpression() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("nanInArithmeticExpression")) return; logChecker("CheckOther::checkNanInArithmeticExpression"); // style for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) { @@ -2078,7 +2087,7 @@ void CheckOther::checkMisusedScopedObject() if (mTokenizer->isC()) return; - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedScopedObject")) return; logChecker("CheckOther::checkMisusedScopedObject"); // style,c++ @@ -2708,7 +2717,7 @@ void CheckOther::checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* to //--------------------------------------------------------------------------- void CheckOther::checkSignOfUnsignedVariable() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unsignedLessThanZero")) return; logChecker("CheckOther::checkSignOfUnsignedVariable"); // style @@ -3115,7 +3124,7 @@ void CheckOther::varFuncNullUBError(const Token *tok) void CheckOther::checkRedundantPointerOp() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("redundantPointerOp")) return; logChecker("CheckOther::checkRedundantPointerOp"); // style @@ -3207,7 +3216,7 @@ void CheckOther::raceAfterInterlockedDecrementError(const Token* tok) void CheckOther::checkUnusedLabel() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("unusedLabel")) return; logChecker("CheckOther::checkUnusedLabel"); // style,warning @@ -3415,7 +3424,7 @@ void CheckOther::checkFuncArgNamesDifferent() const bool inconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive); const bool warning = mSettings->severity.isEnabled(Severity::warning); - if (!(warning || (style && inconclusive))) + if (!(warning || (style && inconclusive)) && !mSettings->isPremiumEnabled("funcArgNamesDifferent")) return; logChecker("CheckOther::checkFuncArgNamesDifferent"); // style,warning,inconclusive @@ -3556,7 +3565,7 @@ static const Token *findShadowed(const Scope *scope, const std::string &varname, void CheckOther::checkShadowVariables() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("shadowVariables")) return; logChecker("CheckOther::checkShadowVariables"); // style const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -3637,7 +3646,7 @@ static bool isVariableExprHidden(const Token* tok) void CheckOther::checkKnownArgument() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("knownArgument")) return; logChecker("CheckOther::checkKnownArgument"); // style const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -3738,7 +3747,7 @@ void CheckOther::knownArgumentError(const Token *tok, const Token *ftok, const V void CheckOther::checkKnownPointerToBool() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("knownPointerToBool")) return; logChecker("CheckOther::checkKnownPointerToBool"); // style const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -3837,7 +3846,7 @@ void CheckOther::comparePointersError(const Token *tok, const ValueFlow::Value * void CheckOther::checkModuloOfOne() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("moduloofone")) return; logChecker("CheckOther::checkModuloOfOne"); // style diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index 7e0b9547d85..a1a9787e0f3 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -1789,7 +1789,7 @@ void CheckStl::sizeError(const Token *tok) void CheckStl::redundantCondition() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("redundantIfRemove")) return; logChecker("CheckStl::redundantCondition"); // style @@ -2843,7 +2843,7 @@ namespace { void CheckStl::useStlAlgorithm() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("useStlAlgorithm")) return; logChecker("CheckStl::useStlAlgorithm"); // style @@ -3075,7 +3075,7 @@ static bool isKnownEmptyContainer(const Token* tok) void CheckStl::knownEmptyContainer() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("knownEmptyContainer")) return; logChecker("CheckStl::knownEmptyContainer"); // style for (const Scope *function : mTokenizer->getSymbolDatabase()->functionScopes) { diff --git a/lib/checktype.cpp b/lib/checktype.cpp index b8a3d26d448..733debc60e7 100644 --- a/lib/checktype.cpp +++ b/lib/checktype.cpp @@ -322,7 +322,7 @@ static bool checkTypeCombination(const ValueType& src, const ValueType& tgt, con void CheckType::checkLongCast() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("truncLongCastAssignment")) return; logChecker("CheckType::checkLongCast"); // style diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index 101c886fe91..55ae8008a22 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -1149,7 +1149,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const void CheckUnusedVar::checkFunctionVariableUsage() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->checkLibrary) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->checkLibrary && !mSettings->isPremiumEnabled("unusedVariable")) return; logChecker("CheckUnusedVar::checkFunctionVariableUsage"); // style @@ -1400,7 +1400,7 @@ void CheckUnusedVar::checkFunctionVariableUsage() void CheckUnusedVar::unusedVariableError(const Token *tok, const std::string &varname) { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedVariable")) return; reportError(tok, Severity::style, "unusedVariable", "$symbol:" + varname + "\nUnused variable: $symbol", CWE563, Certainty::normal); @@ -1408,7 +1408,7 @@ void CheckUnusedVar::unusedVariableError(const Token *tok, const std::string &va void CheckUnusedVar::allocatedButUnusedVariableError(const Token *tok, const std::string &varname) { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedVariable")) return; reportError(tok, Severity::style, "unusedAllocatedMemory", "$symbol:" + varname + "\nVariable '$symbol' is allocated memory that is never used.", CWE563, Certainty::normal); @@ -1416,7 +1416,7 @@ void CheckUnusedVar::allocatedButUnusedVariableError(const Token *tok, const std void CheckUnusedVar::unreadVariableError(const Token *tok, const std::string &varname, bool modified) { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedVariable")) return; if (modified) @@ -1427,7 +1427,7 @@ void CheckUnusedVar::unreadVariableError(const Token *tok, const std::string &va void CheckUnusedVar::unassignedVariableError(const Token *tok, const std::string &varname) { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedVariable")) return; reportError(tok, Severity::style, "unassignedVariable", "$symbol:" + varname + "\nVariable '$symbol' is not assigned a value.", CWE665, Certainty::normal); @@ -1438,7 +1438,7 @@ void CheckUnusedVar::unassignedVariableError(const Token *tok, const std::string //--------------------------------------------------------------------------- void CheckUnusedVar::checkStructMemberUsage() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedVariable")) return; logChecker("CheckUnusedVar::checkStructMemberUsage"); // style diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 9f912697db8..b74d93dbed2 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -1456,8 +1456,7 @@ void CppCheck::executeAddons(const std::vector& files, const std::s errmsg.id = obj["addon"].get() + "-" + obj["errorId"].get(); if (misraC2023 && startsWith(errmsg.id, "misra-c2012-")) errmsg.id = "misra-c2023-" + errmsg.id.substr(12); - const std::string text = obj["message"].get(); - errmsg.setmsg(text); + errmsg.setmsg(mSettings.getMisraRuleText(errmsg.id, obj["message"].get())); const std::string severity = obj["severity"].get(); errmsg.severity = severityFromString(severity); if (errmsg.severity == Severity::none || errmsg.severity == Severity::internal) { @@ -1465,8 +1464,12 @@ void CppCheck::executeAddons(const std::vector& files, const std::s continue; errmsg.severity = Severity::internal; } - else if (!mSettings.severity.isEnabled(errmsg.severity)) - continue; + else if (!mSettings.severity.isEnabled(errmsg.severity)) { + // Do not filter out premium misra/cert/autosar messages that has been + // explicitly enabled with a --premium option + if (!isPremiumCodingStandardId(errmsg.id)) + continue; + } errmsg.file0 = file0; reportErr(errmsg); @@ -1859,3 +1862,15 @@ void CppCheck::printTimerResults(SHOWTIME_MODES mode) { s_timerResults.showResults(mode); } + +bool CppCheck::isPremiumCodingStandardId(const std::string& id) const { + if (mSettings.premiumArgs.find("--misra") != std::string::npos) { + if (startsWith(id, "misra-") || startsWith(id, "premium-misra-")) + return true; + } + if (mSettings.premiumArgs.find("--cert") != std::string::npos && startsWith(id, "premium-cert-")) + return true; + if (mSettings.premiumArgs.find("--autosar") != std::string::npos && startsWith(id, "premium-autosar-")) + return true; + return false; +} diff --git a/lib/cppcheck.h b/lib/cppcheck.h index 8f31d5d75d9..77003e98eff 100644 --- a/lib/cppcheck.h +++ b/lib/cppcheck.h @@ -150,6 +150,10 @@ class CPPCHECKLIB CppCheck : ErrorLogger { static void resetTimerResults(); static void printTimerResults(SHOWTIME_MODES mode); + bool isPremiumCodingStandardId(const std::string& id) const; + + std::string getAddonMessage(const std::string& id, const std::string& text) const; + private: #ifdef HAVE_RULES /** Are there "simple" rules */ diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index efad79ac3f7..be5e8ee7e88 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -750,6 +750,7 @@ bool Preprocessor::hasErrors(const simplecpp::Output &output) case simplecpp::Output::SYNTAX_ERROR: case simplecpp::Output::UNHANDLED_CHAR_ERROR: case simplecpp::Output::EXPLICIT_INCLUDE_NOT_FOUND: + case simplecpp::Output::FILE_NOT_FOUND: return true; case simplecpp::Output::WARNING: case simplecpp::Output::MISSING_HEADER: @@ -889,6 +890,7 @@ void Preprocessor::reportOutput(const simplecpp::OutputList &outputList, bool sh error(out.location.file(), out.location.line, out.msg); break; case simplecpp::Output::EXPLICIT_INCLUDE_NOT_FOUND: + case simplecpp::Output::FILE_NOT_FOUND: error(emptyString, 0, out.msg); break; } diff --git a/lib/settings.cpp b/lib/settings.cpp index a58e75b2c21..9b18f72cdb4 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -22,6 +22,7 @@ #include "vfvalue.h" #include +#include #include "json.h" @@ -125,7 +126,7 @@ std::string Settings::loadCppcheckCfg() const auto& v = it->second; if (!v.is()) return "'safety' is not a bool"; - safety = v.get(); + safety = safety || v.get(); } } @@ -253,3 +254,314 @@ void Settings::setCheckLevelNormal() performanceValueFlowMaxSubFunctionArgs = 8; performanceValueFlowMaxIfCount = 100; } + +// TODO: auto generate these tables + +static const std::set autosarCheckers{ + "accessMoved", + "argumentSize", + "arrayIndexOutOfBounds", + "arrayIndexOutOfBoundsCond", + "arrayIndexThenCheck", + "bufferAccessOutOfBounds", + "comparePointers", + "constParameter", + "cstyleCast", + "ctuOneDefinitionViolation", + "doubleFree", + "duplInheritedMember", + "duplicateBreak", + "funcArgNamesDifferent", + "functionConst", + "functionStatic", + "invalidContainer", + "memleak", + "mismatchAllocDealloc", + "missingReturn", + "negativeIndex", + "noExplicitConstructor", + "nullPointer", + "nullPointerArithmetic", + "nullPointerArithmeticRedundantCheck", + "nullPointerDefaultArg", + "nullPointerRedundantCheck", + "objectIndex", + "overlappingWriteFunction", + "overlappingWriteUnion", + "pointerOutOfBounds", + "pointerOutOfBoundsCond", + "preprocessorErrorDirective", + "redundantAssignment", + "redundantInitialization", + "returnDanglingLifetime", + "shiftTooManyBits", + "sizeofSideEffects", + "throwInDestructor", + "throwInNoexceptFunction", + "uninitData", + "uninitMember", + "unreachableCode", + "unreadVariable", + "unsignedLessThanZero", + "unusedFunction", + "unusedStructMember", + "unusedValue", + "unusedVariable", + "useInitializerList", + "variableScope", + "virtualCallInConstructor", + "zerodiv", + "zerodivcond" +}; + +static const std::set certCCheckers{ + "IOWithoutPositioning", + "autoVariables", + "autovarInvalidDeallocation", + "bitwiseOnBoolean", + "comparePointers", + "danglingLifetime", + "deallocret", + "deallocuse", + "doubleFree", + "floatConversionOverflow", + "invalidFunctionArg", + "invalidLengthModifierError", + "invalidLifetime", + "invalidScanfFormatWidth", + "invalidscanf", + "leakReturnValNotUsed", + "leakUnsafeArgAlloc", + "memleak", + "memleakOnRealloc", + "mismatchAllocDealloc", + "missingReturn", + "nullPointer", + "nullPointerArithmetic", + "nullPointerArithmeticRedundantCheck", + "nullPointerDefaultArg", + "nullPointerRedundantCheck", + "preprocessorErrorDirective", + "resourceLeak", + "sizeofCalculation", + "stringLiteralWrite", + "uninitStructMember", + "uninitdata", + "uninitvar", + "unknownEvaluationOrder", + "useClosedFile", + "wrongPrintfScanfArgNum", + "wrongPrintfScanfParameterPositionError" +}; + +static const std::set certCppCheckers{ + "IOWithoutPositioning", + "accessMoved", + "comparePointers", + "containerOutOfBounds", + "ctuOneDefinitionViolation", + "deallocMismatch", + "deallocThrow", + "deallocuse", + "doubleFree", + "eraseDereference", + "exceptThrowInDestructor", + "initializerList", + "invalidContainer", + "lifetime", + "memleak", + "missingReturn", + "nullPointer", + "operatorEqToSelf", + "sizeofCalculation", + "uninitvar", + "virtualCallInConstructor", + "virtualDestructor" +}; + +static const std::set misrac2012Checkers{ + "alwaysFalse", + "alwaysTrue", + "argumentSize", + "autovarInvalidDeallocation", + "bufferAccessOutOfBounds", + "comparePointers", + "compareValueOutOfTypeRangeError", + "constPointer", + "danglingLifetime", + "duplicateBreak", + "error", + "funcArgNamesDifferent", + "incompatibleFileOpen", + "invalidFunctionArg", + "knownConditionTrueFalse", + "leakNoVarFunctionCall", + "leakReturnValNotUsed", + "memleak", + "memleakOnRealloc", + "missingReturn", + "overlappingWriteFunction", + "overlappingWriteUnion", + "pointerOutOfBounds", + "preprocessorErrorDirective", + "redundantAssignInSwitch", + "redundantAssignment", + "redundantCondition", + "resourceLeak", + "shadowVariable", + "sizeofCalculation", + "syntaxError", + "uninitvar", + "unknownEvaluationOrder", + "unreadVariable", + "unusedLabel", + "unusedVariable", + "useClosedFile", + "writeReadOnlyFile" +}; + +static const std::set misrac2023Checkers{ + "alwaysFalse", + "alwaysTrue", + "argumentSize", + "autovarInvalidDeallocation", + "bufferAccessOutOfBounds", + "comparePointers", + "compareValueOutOfTypeRangeError", + "constPointer", + "danglingLifetime", + "duplicateBreak", + "error", + "funcArgNamesDifferent", + "incompatibleFileOpen", + "invalidFunctionArg", + "knownConditionTrueFalse", + "leakNoVarFunctionCall", + "leakReturnValNotUsed", + "memleak", + "memleakOnRealloc", + "missingReturn", + "overlappingWriteFunction", + "overlappingWriteUnion", + "pointerOutOfBounds", + "preprocessorErrorDirective", + "redundantAssignInSwitch", + "redundantAssignment", + "redundantCondition", + "resourceLeak", + "shadowVariable", + "sizeofCalculation", + "syntaxError", + "uninitvar", + "unknownEvaluationOrder", + "unreadVariable", + "unusedLabel", + "unusedVariable", + "useClosedFile", + "writeReadOnlyFile" +}; + +static const std::set misracpp2008Checkers{ + "autoVariables", + "comparePointers", + "constParameter", + "constVariable", + "cstyleCast", + "ctuOneDefinitionViolation", + "danglingLifetime", + "duplInheritedMember", + "duplicateBreak", + "exceptThrowInDestructor", + "funcArgNamesDifferent", + "functionConst", + "functionStatic", + "missingReturn", + "noExplicit", + "overlappingWriteFunction", + "overlappingWriteUnion", + "pointerOutOfBounds", + "preprocessorErrorDirective", + "redundantAssignment", + "redundantInitialization", + "returnReference", + "returnTempReference", + "shadowVariable", + "shiftTooManyBits", + "sizeofSideEffects", + "throwInDestructor", + "uninitDerivedMemberVar", + "uninitDerivedMemberVarPrivate", + "uninitMemberVar", + "uninitMemberVarPrivate", + "uninitStructMember", + "uninitdata", + "uninitvar", + "unknownEvaluationOrder", + "unreachableCode", + "unreadVariable", + "unsignedLessThanZero", + "unusedFunction", + "unusedStructMember", + "unusedVariable", + "varScope", + "variableScope", + "virtualCallInConstructor" +}; + +bool Settings::isPremiumEnabled(const char id[]) const +{ + if (premiumArgs.find("autosar") != std::string::npos && autosarCheckers.count(id)) + return true; + if (premiumArgs.find("cert-c-") != std::string::npos && certCCheckers.count(id)) + return true; + if (premiumArgs.find("cert-c++") != std::string::npos && certCppCheckers.count(id)) + return true; + if (premiumArgs.find("misra-c-") != std::string::npos && (misrac2012Checkers.count(id) || misrac2023Checkers.count(id))) + return true; + if (premiumArgs.find("misra-c++") != std::string::npos && misracpp2008Checkers.count(id)) + return true; + return false; +} + +void Settings::setMisraRuleTexts(const ExecuteCmdFn& executeCommand) +{ + if (premiumArgs.find("--misra-c-20") != std::string::npos) { + const auto it = std::find_if(addonInfos.cbegin(), addonInfos.cend(), [](const AddonInfo& a) { + return a.name == "premiumaddon.json"; + }); + if (it != addonInfos.cend()) { + std::string arg; + if (premiumArgs.find("--misra-c-2023") != std::string::npos) + arg = "--misra-c-2023-rule-texts"; + else + arg = "--misra-c-2012-rule-texts"; + std::string output; + executeCommand(it->executable, {arg}, "2>&1", output); + setMisraRuleTexts(output); + } + } +} + +void Settings::setMisraRuleTexts(const std::string& data) +{ + mMisraRuleTexts.clear(); + std::istringstream istr(data); + std::string line; + while (std::getline(istr, line)) { + std::string::size_type pos = line.find(' '); + if (pos == std::string::npos) + continue; + std::string id = line.substr(0, pos); + std::string text = line.substr(pos + 1); + if (id.empty() || text.empty()) + continue; + mMisraRuleTexts[id] = text; + } +} + +std::string Settings::getMisraRuleText(const std::string& id, const std::string& text) const { + if (id.compare(0, 9, "misra-c20") != 0) + return text; + const auto it = mMisraRuleTexts.find(id.substr(id.rfind('-') + 1)); + return it != mMisraRuleTexts.end() ? it->second : text; +} diff --git a/lib/settings.h b/lib/settings.h index be106ef98c3..a1692d8ae64 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -263,6 +263,9 @@ class CPPCHECKLIB WARN_UNUSED Settings { /** @brief Extra arguments for Cppcheck Premium addon */ std::string premiumArgs; + /** Is checker id enabled by premiumArgs */ + bool isPremiumEnabled(const char id[]) const; + /** @brief Using -E for debugging purposes */ bool preprocessOnly{}; @@ -446,9 +449,15 @@ class CPPCHECKLIB WARN_UNUSED Settings { void setCheckLevelExhaustive(); void setCheckLevelNormal(); + using ExecuteCmdFn = std::function,std::string,std::string&)>; + void setMisraRuleTexts(const ExecuteCmdFn& executeCommand); + void setMisraRuleTexts(const std::string& data); + std::string getMisraRuleText(const std::string& id, const std::string& text) const; + private: static std::string parseEnabled(const std::string &str, std::tuple, SimpleEnableGroup> &groups); std::string applyEnabled(const std::string &str, bool enable); + std::map mMisraRuleTexts; }; /// @} diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 04db01b8f71..a32c4d35fab 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -138,11 +138,11 @@ static void bailoutInternal(const std::string& type, const TokenList &tokenlist, errorLogger->reportErr(errmsg); } -#define bailout2(type, tokenlist, errorLogger, tok, what) bailoutInternal(type, tokenlist, errorLogger, tok, what, __FILE__, __LINE__, __func__) +#define bailout2(type, tokenlist, errorLogger, tok, what) bailoutInternal((type), (tokenlist), (errorLogger), (tok), (what), __FILE__, __LINE__, __func__) -#define bailout(tokenlist, errorLogger, tok, what) bailout2("valueFlowBailout", tokenlist, errorLogger, tok, what) +#define bailout(tokenlist, errorLogger, tok, what) bailout2("valueFlowBailout", (tokenlist), (errorLogger), (tok), (what)) -#define bailoutIncompleteVar(tokenlist, errorLogger, tok, what) bailoutInternal("valueFlowBailoutIncompleteVar", tokenlist, errorLogger, tok, what, "", 0, __func__) +#define bailoutIncompleteVar(tokenlist, errorLogger, tok, what) bailoutInternal("valueFlowBailoutIncompleteVar", (tokenlist), (errorLogger), (tok), (what), "", 0, __func__) static std::string debugString(const ValueFlow::Value& v) { @@ -9415,7 +9415,7 @@ static ValueFlowPassAdaptor makeValueFlowPassAdaptor(const char* name, bool c #define VALUEFLOW_ADAPTOR(cpp, ...) \ makeValueFlowPassAdaptor(#__VA_ARGS__, \ - cpp, \ + (cpp), \ [](TokenList& tokenlist, \ SymbolDatabase& symboldatabase, \ ErrorLogger* errorLogger, \ diff --git a/lib/version.h b/lib/version.h index 85bb170338f..d104cba18eb 100644 --- a/lib/version.h +++ b/lib/version.h @@ -5,9 +5,9 @@ #define versionH #define CPPCHECK_MAJOR_VERSION 2 -#define CPPCHECK_MINOR_VERSION 12 +#define CPPCHECK_MINOR_VERSION 13 #define CPPCHECK_DEVMINOR_VERSION 13 -#define CPPCHECK_FIX_VERSION 0 +#define CPPCHECK_FIX_VERSION 4 #define STRINGIFY(x) STRING(x) #define STRING(VER) #VER diff --git a/lib/vfvalue.cpp b/lib/vfvalue.cpp index b07a2c57304..44155c0eccf 100644 --- a/lib/vfvalue.cpp +++ b/lib/vfvalue.cpp @@ -115,6 +115,7 @@ namespace ValueFlow { case ValueType::LIFETIME: return "lifetime=" + tokvalue->str(); case ValueType::SYMBOLIC: + { std::string result = "symbolic=" + tokvalue->expressionString(); if (intvalue > 0) result += "+" + std::to_string(intvalue); @@ -122,6 +123,7 @@ namespace ValueFlow { result += "-" + std::to_string(-intvalue); return result; } + } throw InternalError(nullptr, "Invalid ValueFlow Value type"); } diff --git a/man/manual.md b/man/manual.md index 819760925a7..3767f9a736e 100644 --- a/man/manual.md +++ b/man/manual.md @@ -1,6 +1,6 @@ --- title: Cppcheck manual -subtitle: Version 2.12.99 +subtitle: Version 2.13 author: Cppcheck team lang: en documentclass: report diff --git a/man/reference-cfg-format.md b/man/reference-cfg-format.md index 70ff8b95918..a330f003e51 100644 --- a/man/reference-cfg-format.md +++ b/man/reference-cfg-format.md @@ -1,6 +1,6 @@ --- title: Cppcheck .cfg format -subtitle: Version 2.12.99 +subtitle: Version 2.13 author: Cppcheck team lang: en documentclass: report diff --git a/man/writing-addons.md b/man/writing-addons.md index 63b5a2ca0d5..3016a4cb5c8 100644 --- a/man/writing-addons.md +++ b/man/writing-addons.md @@ -1,6 +1,6 @@ --- title: Writing addons -subtitle: Version 2.12.99 +subtitle: Version 2.13 author: Cppcheck team lang: en documentclass: report diff --git a/releasenotes.txt b/releasenotes.txt index 593f61498c8..a8e292f746a 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -1,46 +1,4 @@ -Release Notes for Cppcheck 2.13 +Release Notes for Cppcheck 2.13.4 -New checks: -- passedByValueCallback for functions which take a parameter by value but are used as callbacks (subset of passedByValue) -- returnImplicitInt for C functions without return type (previously reported as a debug message) -- iterateByValue for iterating by value in a range-based for loop when a const reference could be used - -Improved checking: -- - -GUI: -- - -Changed interface: -- Final report of active checkers is reported as a normal information message instead. - -Deprecations: -- "--showtime=top5" has been deprecated and will be removed in Cppcheck 2.14. Please use --showtime=top5_file or --showtime=top5_summary instead. -- Building with Qt5 has been deprecated (it went EOL in May 2023) and will be removed in a future version - please use Qt6 instead. - -Other: -- Windows builds now default to the `native` platform instead of `win32A` or `win64`. Please specify it explicitly if you depend on it. -- The undocumented and deprecated command-line options `--template