Skip to content

Commit 38abecc

Browse files
authored
added command-line option --disable=<id> to disable individual checks (danmar#4712)
1 parent 7945b83 commit 38abecc

File tree

9 files changed

+300
-9
lines changed

9 files changed

+300
-9
lines changed

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ TESTOBJ = test/options.o \
301301
test/testpreprocessor.o \
302302
test/testprocessexecutor.o \
303303
test/testrunner.o \
304+
test/testsettings.o \
304305
test/testsimplifytemplate.o \
305306
test/testsimplifytokens.o \
306307
test/testsimplifytypedef.o \
@@ -768,6 +769,9 @@ test/testprocessexecutor.o: test/testprocessexecutor.cpp cli/executor.h cli/proc
768769
test/testrunner.o: test/testrunner.cpp externals/simplecpp/simplecpp.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/preprocessor.h lib/suppressions.h test/options.h test/testsuite.h
769770
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testrunner.cpp
770771

772+
test/testsettings.o: test/testsettings.cpp lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h test/testsuite.h
773+
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsettings.cpp
774+
771775
test/testsimplifytemplate.o: test/testsimplifytemplate.cpp lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h
772776
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsimplifytemplate.cpp
773777

cli/cmdlineparser.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,14 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[])
299299
else if (std::strcmp(argv[i], "--debug-warnings") == 0)
300300
mSettings->debugwarnings = true;
301301

302+
else if (std::strncmp(argv[i], "--disable=", 10) == 0) {
303+
const std::string errmsg = mSettings->removeEnabled(argv[i] + 10);
304+
if (!errmsg.empty()) {
305+
printError(errmsg);
306+
return false;
307+
}
308+
}
309+
302310
// documentation..
303311
else if (std::strcmp(argv[i], "--doc") == 0) {
304312
std::ostringstream doc;
@@ -321,13 +329,14 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[])
321329
mSettings->dump = true;
322330

323331
else if (std::strncmp(argv[i], "--enable=", 9) == 0) {
324-
const std::string errmsg = mSettings->addEnabled(argv[i] + 9);
332+
const std::string enable_arg = argv[i] + 9;
333+
const std::string errmsg = mSettings->addEnabled(enable_arg);
325334
if (!errmsg.empty()) {
326335
printError(errmsg);
327336
return false;
328337
}
329338
// when "style" is enabled, also enable "warning", "performance" and "portability"
330-
if (mSettings->severity.isEnabled(Severity::style)) {
339+
if (enable_arg.find("style") != std::string::npos) {
331340
mSettings->addEnabled("warning");
332341
mSettings->addEnabled("performance");
333342
mSettings->addEnabled("portability");
@@ -1084,6 +1093,9 @@ void CmdLineParser::printHelp()
10841093
" be considered for evaluation.\n"
10851094
" --config-excludes-file=<file>\n"
10861095
" A file that contains a list of config-excludes\n"
1096+
" --disable=<id> Disable individual checks.\n"
1097+
" Please refer to the documentation of --enable=<id>\n"
1098+
" for futher details.\n"
10871099
" --dump Dump xml data for each translation unit. The dump\n"
10881100
" files have the extension .dump and contain ast,\n"
10891101
" tokenlist, symboldatabase, valueflow.\n"

lib/settings.cpp

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ void Settings::loadCppcheckCfg()
113113
}
114114
}
115115

116-
std::string Settings::addEnabled(const std::string &str)
116+
std::string Settings::parseEnabled(const std::string &str, std::tuple<SimpleEnableGroup<Severity::SeverityType>, SimpleEnableGroup<Checks>> &groups)
117117
{
118118
// Enable parameters may be comma separated...
119119
if (str.find(',') != std::string::npos) {
@@ -122,19 +122,26 @@ std::string Settings::addEnabled(const std::string &str)
122122
while ((pos = str.find(',', pos)) != std::string::npos) {
123123
if (pos == prevPos)
124124
return std::string("--enable parameter is empty");
125-
const std::string errmsg(addEnabled(str.substr(prevPos, pos - prevPos)));
125+
std::string errmsg(parseEnabled(str.substr(prevPos, pos - prevPos), groups));
126126
if (!errmsg.empty())
127127
return errmsg;
128128
++pos;
129129
prevPos = pos;
130130
}
131131
if (prevPos >= str.length())
132132
return std::string("--enable parameter is empty");
133-
return addEnabled(str.substr(prevPos));
133+
return parseEnabled(str.substr(prevPos), groups);
134134
}
135135

136+
auto& severity = std::get<0>(groups);
137+
auto& checks = std::get<1>(groups);
138+
136139
if (str == "all") {
137-
severity.fill();
140+
// "error" is always enabled and cannot be controlled - so exclude it from "all"
141+
SimpleEnableGroup<Severity::SeverityType> newSeverity;
142+
newSeverity.fill();
143+
newSeverity.disable(Severity::SeverityType::error);
144+
severity.enable(newSeverity);
138145
checks.enable(Checks::missingInclude);
139146
checks.enable(Checks::unusedFunction);
140147
} else if (str == "warning") {
@@ -159,13 +166,46 @@ std::string Settings::addEnabled(const std::string &str)
159166
}
160167
#endif
161168
else {
169+
// the actual option is prepending in the applyEnabled() call
162170
if (str.empty())
163-
return std::string("cppcheck: --enable parameter is empty");
171+
return " parameter is empty";
164172
else
165-
return std::string("cppcheck: there is no --enable parameter with the name '" + str + "'");
173+
return " parameter with the unknown name '" + str + "'";
166174
}
167175

168-
return std::string();
176+
return "";
177+
}
178+
179+
std::string Settings::addEnabled(const std::string &str)
180+
{
181+
return applyEnabled(str, true);
182+
}
183+
184+
std::string Settings::removeEnabled(const std::string &str)
185+
{
186+
return applyEnabled(str, false);
187+
}
188+
189+
std::string Settings::applyEnabled(const std::string &str, bool enable)
190+
{
191+
std::tuple<SimpleEnableGroup<Severity::SeverityType>, SimpleEnableGroup<Checks>> groups;
192+
std::string errmsg = parseEnabled(str, groups);
193+
if (!errmsg.empty())
194+
return (enable ? "--enable" : "--disable") + errmsg;
195+
196+
const auto s = std::get<0>(groups);
197+
const auto c = std::get<1>(groups);
198+
if (enable) {
199+
severity.enable(s);
200+
checks.enable(c);
201+
}
202+
else {
203+
severity.disable(s);
204+
checks.disable(c);
205+
}
206+
// FIXME: hack to make sure "error" is always enabled
207+
severity.enable(Severity::SeverityType::error);
208+
return errmsg;
169209
}
170210

171211
bool Settings::isEnabled(const ValueFlow::Value *value, bool inconclusiveCheck) const

lib/settings.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <list>
3737
#include <set>
3838
#include <string>
39+
#include <tuple>
3940
#include <vector>
4041
#include <unordered_set>
4142

@@ -71,9 +72,15 @@ class SimpleEnableGroup {
7172
void enable(T flag) {
7273
mFlags |= (1U << (uint32_t)flag);
7374
}
75+
void enable(SimpleEnableGroup<T> group) {
76+
mFlags |= group.intValue();
77+
}
7478
void disable(T flag) {
7579
mFlags &= ~(1U << (uint32_t)flag);
7680
}
81+
void disable(SimpleEnableGroup<T> group) {
82+
mFlags &= ~(group.intValue());
83+
}
7784
void setEnabled(T flag, bool enabled) {
7885
if (enabled)
7986
enable(flag);
@@ -393,6 +400,14 @@ class CPPCHECKLIB Settings : public cppcheck::Platform {
393400
*/
394401
std::string addEnabled(const std::string &str);
395402

403+
/**
404+
* @brief Disable extra checks by id
405+
* @param str single id or list of id values to be enabled
406+
* or empty string to enable all. e.g. "style,possibleError"
407+
* @return error message. empty upon success
408+
*/
409+
std::string removeEnabled(const std::string &str);
410+
396411
/**
397412
* @brief Returns true if given value can be shown
398413
* @return true if the value can be shown
@@ -417,6 +432,10 @@ class CPPCHECKLIB Settings : public cppcheck::Platform {
417432
std::set<std::string> summaryReturn;
418433

419434
void loadSummaries();
435+
436+
private:
437+
static std::string parseEnabled(const std::string &str, std::tuple<SimpleEnableGroup<Severity::SeverityType>, SimpleEnableGroup<Checks>> &groups);
438+
std::string applyEnabled(const std::string &str, bool enable);
420439
};
421440

422441
/// @}

man/cppcheck.1.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
105105
<arg choice="opt">
106106
<option>-U&lt;id&gt;</option>
107107
</arg>
108+
<arg choice="opt">
109+
<option>--disable=&lt;id&gt;</option>
110+
</arg>
108111
<arg choice="opt">
109112
<option>--enable=&lt;id&gt;</option>
110113
</arg>
@@ -272,6 +275,15 @@ Example: -DDEBUG=1 -D__cplusplus</para>
272275
Example: '-UDEBUG'</para>
273276
</listitem>
274277
</varlistentry>
278+
<varlistentry>
279+
<term>
280+
<option>--disable=&lt;id&gt;</option>
281+
</term>
282+
<listitem>
283+
<para>Disable individual checks. Please refer to the documentation of --enable=&lt;id&gt; for futher details.
284+
</para>
285+
</listitem>
286+
</varlistentry>
275287
<varlistentry>
276288
<term>
277289
<option>--enable=&lt;id&gt;</option>

releasenotes.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ release notes for cppcheck-2.10
22

33
- the deprecated Makefile option SRCDIR is no longer accepted
44
- if the file provided via "--file-list" cannot be opened it will now error out
5+
- add command-line option "--disable=<id>" to individually disable checks

test/testcmdlineparser.cpp

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,15 @@ class TestCmdlineParser : public TestFixture {
8888
TEST_CASE(enabledInternal);
8989
#endif
9090
TEST_CASE(enabledMultiple);
91+
TEST_CASE(enabledInvalid);
92+
TEST_CASE(enabledError);
93+
TEST_CASE(enabledEmpty);
94+
TEST_CASE(disableAll);
95+
TEST_CASE(disableMultiple);
96+
TEST_CASE(disableStylePartial);
97+
TEST_CASE(disableInvalid);
98+
TEST_CASE(disableError);
99+
TEST_CASE(disableEmpty);
91100
TEST_CASE(inconclusive);
92101
TEST_CASE(errorExitcode);
93102
TEST_CASE(errorExitcodeMissing);
@@ -654,6 +663,109 @@ class TestCmdlineParser : public TestFixture {
654663
ASSERT_EQUALS("", GET_REDIRECT_OUTPUT);
655664
}
656665

666+
void enabledInvalid() {
667+
REDIRECT;
668+
const char * const argv[] = {"cppcheck", "--enable=warning,missingIncludeSystem,style", "file.cpp"};
669+
settings = Settings();
670+
ASSERT(!defParser.parseFromArgs(3, argv));
671+
ASSERT_EQUALS("cppcheck: error: --enable parameter with the unknown name 'missingIncludeSystem'\n", GET_REDIRECT_OUTPUT);
672+
}
673+
674+
void enabledError() {
675+
REDIRECT;
676+
const char * const argv[] = {"cppcheck", "--enable=error", "file.cpp"};
677+
settings = Settings();
678+
ASSERT(!defParser.parseFromArgs(3, argv));
679+
ASSERT_EQUALS("cppcheck: error: --enable parameter with the unknown name 'error'\n", GET_REDIRECT_OUTPUT);
680+
}
681+
682+
void enabledEmpty() {
683+
REDIRECT;
684+
const char * const argv[] = {"cppcheck", "--enable=", "file.cpp"};
685+
settings = Settings();
686+
ASSERT(!defParser.parseFromArgs(3, argv));
687+
ASSERT_EQUALS("cppcheck: error: --enable parameter is empty\n", GET_REDIRECT_OUTPUT);
688+
}
689+
690+
void disableAll() {
691+
REDIRECT;
692+
const char * const argv[] = {"cppcheck", "--enable=all", "--disable=all"};
693+
settings.severity.clear();
694+
settings.checks.clear();
695+
ASSERT(defParser.parseFromArgs(3, argv));
696+
ASSERT_EQUALS(true, settings.severity.isEnabled(Severity::error));
697+
ASSERT_EQUALS(false, settings.severity.isEnabled(Severity::warning));
698+
ASSERT_EQUALS(false, settings.severity.isEnabled(Severity::style));
699+
ASSERT_EQUALS(false, settings.severity.isEnabled(Severity::performance));
700+
ASSERT_EQUALS(false, settings.severity.isEnabled(Severity::portability));
701+
ASSERT_EQUALS(false, settings.severity.isEnabled(Severity::debug));
702+
ASSERT_EQUALS(false, settings.checks.isEnabled(Checks::unusedFunction));
703+
ASSERT_EQUALS(false, settings.checks.isEnabled(Checks::missingInclude));
704+
ASSERT_EQUALS(false, settings.checks.isEnabled(Checks::internalCheck));
705+
ASSERT_EQUALS("", GET_REDIRECT_OUTPUT);
706+
}
707+
708+
void disableMultiple() {
709+
REDIRECT;
710+
const char * const argv[] = {"cppcheck", "--enable=all", "--disable=style", "--disable=unusedFunction"};
711+
settings.severity.clear();
712+
settings.checks.clear();
713+
ASSERT(defParser.parseFromArgs(4, argv));
714+
ASSERT_EQUALS(true, settings.severity.isEnabled(Severity::error));
715+
ASSERT_EQUALS(true, settings.severity.isEnabled(Severity::warning));
716+
ASSERT_EQUALS(false, settings.severity.isEnabled(Severity::style));
717+
ASSERT_EQUALS(true, settings.severity.isEnabled(Severity::performance));
718+
ASSERT_EQUALS(true, settings.severity.isEnabled(Severity::portability));
719+
ASSERT_EQUALS(true, settings.severity.isEnabled(Severity::debug));
720+
ASSERT_EQUALS(false, settings.checks.isEnabled(Checks::unusedFunction));
721+
ASSERT_EQUALS(true, settings.checks.isEnabled(Checks::missingInclude));
722+
ASSERT_EQUALS(false, settings.checks.isEnabled(Checks::internalCheck));
723+
ASSERT_EQUALS("", GET_REDIRECT_OUTPUT);
724+
}
725+
726+
// make sure the implied "style" checks are not added when "--enable=style" is specified
727+
void disableStylePartial() {
728+
REDIRECT;
729+
const char * const argv[] = {"cppcheck", "--enable=style", "--disable=performance", "--enable=unusedFunction"};
730+
settings.severity.clear();
731+
settings.checks.clear();
732+
ASSERT(defParser.parseFromArgs(4, argv));
733+
ASSERT_EQUALS(true, settings.severity.isEnabled(Severity::error));
734+
ASSERT_EQUALS(true, settings.severity.isEnabled(Severity::warning));
735+
ASSERT_EQUALS(true, settings.severity.isEnabled(Severity::style));
736+
ASSERT_EQUALS(false, settings.severity.isEnabled(Severity::performance));
737+
ASSERT_EQUALS(true, settings.severity.isEnabled(Severity::portability));
738+
ASSERT_EQUALS(false, settings.severity.isEnabled(Severity::debug));
739+
ASSERT_EQUALS(true, settings.checks.isEnabled(Checks::unusedFunction));
740+
ASSERT_EQUALS(false, settings.checks.isEnabled(Checks::missingInclude));
741+
ASSERT_EQUALS(false, settings.checks.isEnabled(Checks::internalCheck));
742+
ASSERT_EQUALS("", GET_REDIRECT_OUTPUT);
743+
}
744+
745+
void disableInvalid() {
746+
REDIRECT;
747+
const char * const argv[] = {"cppcheck", "--disable=leaks", "file.cpp"};
748+
settings = Settings();
749+
ASSERT(!defParser.parseFromArgs(3, argv));
750+
ASSERT_EQUALS("cppcheck: error: --disable parameter with the unknown name 'leaks'\n", GET_REDIRECT_OUTPUT);
751+
}
752+
753+
void disableError() {
754+
REDIRECT;
755+
const char * const argv[] = {"cppcheck", "--disable=error", "file.cpp"};
756+
settings = Settings();
757+
ASSERT(!defParser.parseFromArgs(3, argv));
758+
ASSERT_EQUALS("cppcheck: error: --disable parameter with the unknown name 'error'\n", GET_REDIRECT_OUTPUT);
759+
}
760+
761+
void disableEmpty() {
762+
REDIRECT;
763+
const char * const argv[] = {"cppcheck", "--disable=", "file.cpp"};
764+
settings = Settings();
765+
ASSERT(!defParser.parseFromArgs(3, argv));
766+
ASSERT_EQUALS("cppcheck: error: --disable parameter is empty\n", GET_REDIRECT_OUTPUT);
767+
}
768+
657769
void inconclusive() {
658770
REDIRECT;
659771
const char * const argv[] = {"cppcheck", "--inconclusive"};

test/testrunner.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
<ClCompile Include="testpreprocessor.cpp" />
7272
<ClCompile Include="testprocessexecutor.cpp" />
7373
<ClCompile Include="testrunner.cpp" />
74+
<ClCompile Include="testsettings.cpp" />
7475
<ClCompile Include="testsimplifytemplate.cpp" />
7576
<ClCompile Include="testsimplifytokens.cpp" />
7677
<ClCompile Include="testsimplifytypedef.cpp" />

0 commit comments

Comments
 (0)