From 231b486e4946c7b406173d49e6848e72d0b4b1ae Mon Sep 17 00:00:00 2001 From: Albert Aribaud Date: Fri, 9 Oct 2015 19:57:05 +0200 Subject: [PATCH] Add a dynamic rule enable/disable system --- cli/cmdlineparser.cpp | 43 ++++++++++++++++++++++++++++++++++--------- lib/cppcheck.cpp | 38 +++++++++++++++++++++++++++++--------- lib/settings.h | 10 ++++++++-- 3 files changed, 71 insertions(+), 20 deletions(-) diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index f535def63..9a64bf797 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -641,43 +641,68 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[]) else if (std::strncmp(argv[i], "--rule=", 7) == 0) { Settings::Rule rule; rule.pattern = 7 + argv[i]; - _settings->rules.push_back(rule); + _settings->rules[rule.id] = rule; } // Rule file else if (std::strncmp(argv[i], "--rule-file=", 12) == 0) { tinyxml2::XMLDocument doc; if (doc.LoadFile(12+argv[i]) == tinyxml2::XML_NO_ERROR) { - tinyxml2::XMLElement *node = doc.FirstChildElement(); + const tinyxml2::XMLElement *node = doc.FirstChildElement(); for (; node && strcmp(node->Value(), "rule") == 0; node = node->NextSiblingElement()) { Settings::Rule rule; - tinyxml2::XMLElement *tokenlist = node->FirstChildElement("tokenlist"); + const tinyxml2::XMLElement *tokenlist = node->FirstChildElement("tokenlist"); if (tokenlist) rule.tokenlist = tokenlist->GetText(); - tinyxml2::XMLElement *pattern = node->FirstChildElement("pattern"); + const tinyxml2::XMLElement *pattern = node->FirstChildElement("pattern"); if (pattern) { rule.pattern = pattern->GetText(); } - tinyxml2::XMLElement *message = node->FirstChildElement("message"); + const tinyxml2::XMLElement *message = node->FirstChildElement("message"); if (message) { - tinyxml2::XMLElement *severity = message->FirstChildElement("severity"); + const tinyxml2::XMLElement *severity = message->FirstChildElement("severity"); if (severity) rule.severity = severity->GetText(); - tinyxml2::XMLElement *id = message->FirstChildElement("id"); + const tinyxml2::XMLElement *id = message->FirstChildElement("id"); if (id) rule.id = id->GetText(); - tinyxml2::XMLElement *summary = message->FirstChildElement("summary"); + const tinyxml2::XMLElement *summary = message->FirstChildElement("summary"); if (summary) rule.summary = summary->GetText() ? summary->GetText() : ""; } + tinyxml2::XMLElement *state = node->FirstChildElement("state"); + if (state) { + std::string rule_state = state->GetText(); + if (rule_state == "enabled") + rule.enabled = true; + else if (rule_state == "disabled") + rule.enabled = false; + else { + std::string msg("cppcheck: error: unrecognized rule state: \""); + msg += rule_state; + msg += "\". Supported states: disable, enable."; + PrintMessage(msg); + } + } + + tinyxml2::XMLElement *disabled = node->FirstChildElement("disable"); + if (disabled) { + rule.disable_rules = disabled->GetText(); + } + + tinyxml2::XMLElement *enabled = node->FirstChildElement("enable"); + if (enabled) { + rule.enable_rules = enabled->GetText(); + } + if (!rule.pattern.empty()) - _settings->rules.push_back(rule); + _settings->rules[rule.id] = rule; } } } diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 9353cde79..7a1eb97a1 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -168,8 +168,8 @@ unsigned int CppCheck::processFile(const std::string& filename, std::istream& fi } // Run rules on this code - for (std::list::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) { - if (it->tokenlist == "define") { + for (std::map::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) { + if (it->second.enabled && it->second.tokenlist == "define") { Tokenizer tokenizer2(&_settings, this); std::istringstream istr2(filedata); tokenizer2.list.createTokens(istr2, filename); @@ -320,8 +320,8 @@ bool CppCheck::checkFile(const std::string &code, const char FileName[], std::se _tokenizer.setTimerResults(&S_timerResults); try { // Execute rules for "raw" code - for (std::list::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) { - if (it->tokenlist == "raw") { + for (std::map::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) { + if (it->second.enabled && it->second.tokenlist == "raw") { Tokenizer tokenizer2(&_settings, this); std::istringstream istr(code); tokenizer2.list.createTokens(istr, FileName); @@ -439,8 +439,8 @@ void CppCheck::executeRules(const std::string &tokenlist, const Tokenizer &token #ifdef HAVE_RULES // Are there rules to execute? bool isrule = false; - for (std::list::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) { - if (it->tokenlist == tokenlist) + for (std::map::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) { + if (it->second.enabled && it->second.tokenlist == tokenlist) isrule = true; } @@ -454,9 +454,9 @@ void CppCheck::executeRules(const std::string &tokenlist, const Tokenizer &token ostr << " " << tok->str(); const std::string str(ostr.str()); - for (std::list::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) { - const Settings::Rule &rule = *it; - if (rule.pattern.empty() || rule.id.empty() || rule.severity.empty() || rule.tokenlist != tokenlist) + for (std::map::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) { + const Settings::Rule &rule = it->second; + if (rule.pattern.empty() || rule.id.empty() || rule.severity.empty() || rule.tokenlist != tokenlist || !rule.enabled) continue; const char *error = nullptr; @@ -511,6 +511,26 @@ void CppCheck::executeRules(const std::string &tokenlist, const Tokenizer &token // Report error reportErr(errmsg); + + // Disable rules that must be disabled + std::istringstream disable(rule.disable_rules); + do { + std::string rule_to_disable; + disable >> rule_to_disable; + if (rule_to_disable != "") { + _settings.rules[rule_to_disable].enabled = false; + } + } while (disable); + + // Enable rules that must be enabled + std::istringstream enable(rule.enable_rules); + do { + std::string rule_to_enable; + enable >> rule_to_enable; + if (rule_to_enable != "") { + _settings.rules[rule_to_enable].enabled = true; + } + } while (enable); } pcre_free(re); diff --git a/lib/settings.h b/lib/settings.h index eb5b65113..b873625c1 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -218,7 +218,10 @@ public: Rule() : tokenlist("simple") // use simple tokenlist , id("rule") // default id - , severity("style") { // default severity + , severity("style") // default severity + , disable_rules("") // default disabled rules + , enable_rules("") // default enabled rules + , enabled(true) { } std::string tokenlist; @@ -226,12 +229,15 @@ public: std::string id; std::string severity; std::string summary; + std::string disable_rules; + std::string enable_rules; + bool enabled; }; /** * @brief Extra rules */ - std::list rules; + std::map rules; /** Is the 'configuration checking' wanted? */ bool checkConfiguration;