diff --git a/addons/misra.py b/addons/misra.py index 2e4b05d06f5..276ba73a374 100755 --- a/addons/misra.py +++ b/addons/misra.py @@ -4280,14 +4280,6 @@ def reportError(self, location, num1, num2): errorId = 'c2012-' + str(num1) + '.' + str(num2) misra_severity = 'Undefined' cppcheck_severity = 'style' - if self.path_premium_addon and ruleNum not in self.ruleTexts: - 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() - rule = Rule(num1, num2) - rule.text = errmsg - self.ruleTexts[rule.num] = rule - break if ruleNum in self.ruleTexts: errmsg = self.ruleTexts[ruleNum].text if self.ruleTexts[ruleNum].misra_severity: diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 3ce9d95944f..e5f04ccd143 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -191,6 +191,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/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/mainwindow.cpp b/gui/mainwindow.cpp index 5695fe02823..a5c6345175f 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" @@ -1090,6 +1091,7 @@ QPair MainWindow::getCppcheckSettings() if (!premiumArgs.contains("misra") && mProjectFile->getAddons().contains("misra")) premiumArgs += " --misra-c-2012"; result.premiumArgs = premiumArgs.mid(1).toStdString(); + result.setMisraRuleTexts(CheckThread::executeCommand); } } diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index cc8829c0a33..29a62661314 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -1473,8 +1473,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) { diff --git a/lib/cppcheck.h b/lib/cppcheck.h index f5ea60f23ed..d7ce0f167b6 100644 --- a/lib/cppcheck.h +++ b/lib/cppcheck.h @@ -152,6 +152,8 @@ class CPPCHECKLIB CppCheck : ErrorLogger { 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/settings.cpp b/lib/settings.cpp index 97a31eaafbc..dd3f057c7ad 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -22,6 +22,7 @@ #include "vfvalue.h" #include +#include #include "json.h" @@ -545,3 +546,46 @@ bool Settings::isPremiumEnabled(const char id[]) const 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 bb95a4aa5aa..e1a53110943 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -261,6 +261,7 @@ 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 */ @@ -452,9 +453,15 @@ class CPPCHECKLIB WARN_UNUSED Settings { }; CheckLevel checkLevel = CheckLevel::normal; + 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/test/testsettings.cpp b/test/testsettings.cpp index a9e8466a2e2..2e7ff77fdc5 100644 --- a/test/testsettings.cpp +++ b/test/testsettings.cpp @@ -32,6 +32,7 @@ class TestSettings : public TestFixture { TEST_CASE(loadCppcheckCfg); TEST_CASE(loadCppcheckCfgSafety); TEST_CASE(getNameAndVersion); + TEST_CASE(ruleTexts); } void simpleEnableGroup() const { @@ -254,6 +255,14 @@ class TestSettings : public TestFixture { ASSERT_EQUALS("12.3.4s", nameVersion.second); } } + + void ruleTexts() const + { + Settings s; + s.setMisraRuleTexts("1.1 text 1\n1.2 text 2\n"); + ASSERT_EQUALS("text 1", s.getMisraRuleText("misra-c2012-1.1", "---")); + ASSERT_EQUALS("text 2", s.getMisraRuleText("misra-c2012-1.2", "---")); + } }; REGISTER_TEST(TestSettings)