From 357261dc698be15908da6c89fec706a1aa1a09fb Mon Sep 17 00:00:00 2001 From: firewave Date: Wed, 3 Apr 2024 11:29:07 +0200 Subject: [PATCH 1/5] Settings: switched order in `CheckLevel` so less/greater than comparisons make sense --- lib/settings.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/settings.h b/lib/settings.h index a824989dac4..b5dc0951d4b 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -460,8 +460,8 @@ class CPPCHECKLIB WARN_UNUSED Settings { void setCheckLevelNormal(); enum class CheckLevel { - exhaustive, - normal + normal, + exhaustive }; CheckLevel checkLevel = CheckLevel::normal; From d2127cba065cdbe5fb83100e0976d54c3d2f7a6a Mon Sep 17 00:00:00 2001 From: firewave Date: Wed, 3 Apr 2024 11:33:04 +0200 Subject: [PATCH 2/5] TestFixture: added `SettingsBuilder::normal()` --- test/fixture.cpp | 5 +++++ test/fixture.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/test/fixture.cpp b/test/fixture.cpp index d3dac189535..024bd004327 100644 --- a/test/fixture.cpp +++ b/test/fixture.cpp @@ -445,6 +445,11 @@ void TestFixture::setTemplateFormat(const std::string &templateFormat) } } +TestFixture::SettingsBuilder& TestFixture::SettingsBuilder::normal() { + settings.setCheckLevelNormal(); + return *this; +} + TestFixture::SettingsBuilder& TestFixture::SettingsBuilder::exhaustive() { settings.setCheckLevelExhaustive(); return *this; diff --git a/test/fixture.h b/test/fixture.h index feda9caf540..17e076546de 100644 --- a/test/fixture.h +++ b/test/fixture.h @@ -210,6 +210,8 @@ class TestFixture : public ErrorLogger { SettingsBuilder& exhaustive(); + SettingsBuilder& normal(); + SettingsBuilder& library(const char lib[]); SettingsBuilder& libraryxml(const char xmldata[], std::size_t len); From ef68c5d944dc896ee17922f3e00b04c6cb9d0832 Mon Sep 17 00:00:00 2001 From: firewave Date: Wed, 3 Apr 2024 11:34:46 +0200 Subject: [PATCH 3/5] default to `--check-level=exhaustive` internally --- cli/cmdlineparser.cpp | 3 + gui/mainwindow.cpp | 3 + lib/importproject.cpp | 3 + lib/settings.cpp | 2 +- lib/settings.h | 6 +- test/testcmdlineparser.cpp | 30 ++++++++++ test/testcondition.cpp | 2 +- test/testgarbage.cpp | 12 ++++ test/testsettings.cpp | 9 +++ test/testsimplifytokens.cpp | 26 +++++---- test/testsimplifytypedef.cpp | 2 +- test/testsimplifyusing.cpp | 5 +- test/testsymboldatabase.cpp | 2 +- test/testtokenize.cpp | 108 +++++++++++++++++++++-------------- test/testvalueflow.cpp | 8 +-- 15 files changed, 157 insertions(+), 64 deletions(-) diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index b0603c9591b..5ae6a7a1ac4 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -311,6 +311,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a { mSettings.exename = Path::getCurrentExecutablePath(argv[0]); + // default to --check-level=normal from CLI for now + mSettings.setCheckLevelNormal(); + if (argc <= 1) { printHelp(); return Result::Exit; diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 9a8ba14504a..2e358a1f0e6 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -969,6 +969,9 @@ QPair MainWindow::getCppcheckSettings() result.exename = QCoreApplication::applicationFilePath().toStdString(); + // default to --check-level=normal for GUI for now + result.setCheckLevelNormal(); + 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.\n\nAnalysis is aborted.").arg("std.cfg")); diff --git a/lib/importproject.cpp b/lib/importproject.cpp index 34780f7cd49..64c9a6428eb 100644 --- a/lib/importproject.cpp +++ b/lib/importproject.cpp @@ -1125,6 +1125,9 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti std::list suppressions; Settings temp; + // default to --check-level=normal for import for now + temp.setCheckLevelNormal(); + guiProject.analyzeAllVsConfigs.clear(); bool checkLevelExhaustive = false; diff --git a/lib/settings.cpp b/lib/settings.cpp index ae03f2476de..d5e226da64d 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -41,7 +41,7 @@ Settings::Settings() { severity.setEnabled(Severity::error, true); certainty.setEnabled(Certainty::normal, true); - setCheckLevelNormal(); + setCheckLevelExhaustive(); executor = defaultExecutor(); } diff --git a/lib/settings.h b/lib/settings.h index b5dc0951d4b..03bf0b9530c 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -259,10 +259,10 @@ class CPPCHECKLIB WARN_UNUSED Settings { int performanceValueFlowMaxTime = -1; /** @brief --performance-valueflow-max-if-count=C */ - int performanceValueFlowMaxIfCount; + int performanceValueFlowMaxIfCount = -1; /** @brief max number of sets of arguments to pass to subfuncions in valueflow */ - int performanceValueFlowMaxSubFunctionArgs; + int performanceValueFlowMaxSubFunctionArgs = 256; /** @brief plist output (--plist-output=<dir>) */ std::string plistOutput; @@ -463,7 +463,7 @@ class CPPCHECKLIB WARN_UNUSED Settings { normal, exhaustive }; - CheckLevel checkLevel = CheckLevel::normal; + CheckLevel checkLevel = CheckLevel::exhaustive; using ExecuteCmdFn = std::function,std::string,std::string&)>; void setMisraRuleTexts(const ExecuteCmdFn& executeCommand); diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index ca187287dcd..a92047363fa 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -383,6 +383,9 @@ class TestCmdlineParser : public TestFixture { #else TEST_CASE(executorProcessNotSupported); #endif + TEST_CASE(checkLevelDefault); + TEST_CASE(checkLevelNormal); + TEST_CASE(checkLevelExhaustive); TEST_CASE(ignorepaths1); TEST_CASE(ignorepaths2); @@ -2565,6 +2568,33 @@ class TestCmdlineParser : public TestFixture { } #endif + void checkLevelDefault() { + REDIRECT; + const char * const argv[] = {"cppcheck", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(2, argv)); + ASSERT_EQUALS_ENUM(Settings::CheckLevel::normal, settings->checkLevel); + ASSERT_EQUALS(100, settings->performanceValueFlowMaxIfCount); + ASSERT_EQUALS(8, settings->performanceValueFlowMaxSubFunctionArgs); + } + + void checkLevelNormal() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--check-level=normal", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS_ENUM(Settings::CheckLevel::normal, settings->checkLevel); + ASSERT_EQUALS(100, settings->performanceValueFlowMaxIfCount); + ASSERT_EQUALS(8, settings->performanceValueFlowMaxSubFunctionArgs); + } + + void checkLevelExhaustive() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--check-level=exhaustive", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS_ENUM(Settings::CheckLevel::exhaustive, settings->checkLevel); + ASSERT_EQUALS(-1, settings->performanceValueFlowMaxIfCount); + ASSERT_EQUALS(256, settings->performanceValueFlowMaxSubFunctionArgs); + } + void ignorepaths1() { REDIRECT; const char * const argv[] = {"cppcheck", "-isrc", "file.cpp"}; diff --git a/test/testcondition.cpp b/test/testcondition.cpp index 7ae5338448f..16b08f6e3ae 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -140,7 +140,7 @@ class TestCondition : public TestFixture { } void check_(const char* file, int line, const char code[], const char* filename = "test.cpp", bool inconclusive = false) { - const Settings settings = settingsBuilder(settings0).certainty(Certainty::inconclusive, inconclusive).exhaustive().build(); + const Settings settings = settingsBuilder(settings0).certainty(Certainty::inconclusive, inconclusive).build(); check_(file, line, code, settings, filename); } diff --git a/test/testgarbage.cpp b/test/testgarbage.cpp index 776d96cd9c5..4ef130526a4 100644 --- a/test/testgarbage.cpp +++ b/test/testgarbage.cpp @@ -498,6 +498,7 @@ class TestGarbage : public TestFixture { void garbageCode16() { checkCode("{ } A() { delete }"); // #6080 + ignore_errout(); // we do not care about the output } void garbageCode17() { @@ -563,6 +564,7 @@ class TestGarbage : public TestFixture { " case struct Tree : break;\n" " }\n" "}"), SYNTAX); + ignore_errout(); // we do not care about the output } void garbageCode26() { @@ -633,10 +635,12 @@ class TestGarbage : public TestFixture { void garbageCode37() { // #5166 segmentation fault (invalid code) in lib/checkother.cpp:329 ( void * f { } void b ( ) { * f } ) checkCode("void * f { } void b ( ) { * f }"); + ignore_errout(); // we do not care about the output } void garbageCode38() { // Ticket #6666 checkCode("{ f2 { } } void f3 () { delete[] } { }"); + ignore_errout(); // we do not care about the output } void garbageCode40() { // #6620 @@ -1222,6 +1226,7 @@ class TestGarbage : public TestFixture { " for (j = 0; j < 1; j)\n" " j6;\n" "}"); + ignore_errout(); // we do not care about the output } void garbageCode150() { // #7089 @@ -1441,6 +1446,7 @@ class TestGarbage : public TestFixture { void garbageCode168() { // 7246 checkCode("long foo(void) { return *bar; }", false); + ignore_errout(); // we do not care about the output } void garbageCode169() { @@ -1581,6 +1587,7 @@ class TestGarbage : public TestFixture { " double e(b);\n" " if(e <= 0) {}\n" "}"); + ignore_errout(); // we do not care about the output } // #8265 @@ -1607,6 +1614,7 @@ class TestGarbage : public TestFixture { // #8752 void garbageCode199() { checkCode("d f(){e n00e0[]n00e0&" "0+f=0}"); + ignore_errout(); // we do not care about the output } // #8757 @@ -1623,6 +1631,7 @@ class TestGarbage : public TestFixture { void garbageCode202() { ASSERT_THROW_INTERNAL(checkCode("void f() { UNKNOWN_MACRO(return); }"), UNKNOWN_MACRO); ASSERT_THROW_INTERNAL(checkCode("void f() { UNKNOWN_MACRO(throw); }"), UNKNOWN_MACRO); + ignore_errout(); } void garbageCode203() { // #8972 @@ -1735,7 +1744,9 @@ class TestGarbage : public TestFixture { } void garbageCode224() { ASSERT_THROW_INTERNAL(checkCode("void f(){ auto* b = dynamic_cast foo* { return new foo(); };\n" "}"); + ignore_errout(); // we do not care about the output } }; diff --git a/test/testsettings.cpp b/test/testsettings.cpp index 803e49dcb54..2e04c568559 100644 --- a/test/testsettings.cpp +++ b/test/testsettings.cpp @@ -36,6 +36,7 @@ class TestSettings : public TestFixture { TEST_CASE(loadCppcheckCfgSafety); TEST_CASE(getNameAndVersion); TEST_CASE(ruleTexts); + TEST_CASE(checkLevelDefault); } void simpleEnableGroup() const { @@ -266,6 +267,14 @@ class TestSettings : public TestFixture { ASSERT_EQUALS("text 1", s.getMisraRuleText("misra-c2012-1.1", "---")); ASSERT_EQUALS("text 2", s.getMisraRuleText("misra-c2012-1.2", "---")); } + + void checkLevelDefault() const + { + Settings s; + ASSERT_EQUALS_ENUM(s.checkLevel, Settings::CheckLevel::exhaustive); + ASSERT_EQUALS(s.performanceValueFlowMaxIfCount, -1); + ASSERT_EQUALS(s.performanceValueFlowMaxSubFunctionArgs, 256); + } }; REGISTER_TEST(TestSettings) diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 3f4aff09885..023b0bef831 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -2031,6 +2031,7 @@ class TestSimplifyTokens : public TestFixture { "a [ x ] = 0 ;\n" "}"; ASSERT_EQUALS(expected, tokenizeAndStringify(code, true)); + ASSERT_EQUALS("[test.cpp:3]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable cin\n", errout_str()); } void simplifyKnownVariables36() { @@ -2147,14 +2148,13 @@ class TestSimplifyTokens : public TestFixture { " return x;\n" "}"; - { - const char expected[] = "void f ( ) {\n" - "int x ; x = 0 ;\n" - "cin >> x ;\n" - "return x ;\n" - "}"; - ASSERT_EQUALS(expected, tokenizeAndStringify(code, true, Platform::Type::Native, true)); - } + const char expected[] = "void f ( ) {\n" + "int x ; x = 0 ;\n" + "cin >> x ;\n" + "return x ;\n" + "}"; + ASSERT_EQUALS(expected, tokenizeAndStringify(code, true, Platform::Type::Native, true)); + ASSERT_EQUALS("[test.cpp:3]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable cin\n", errout_str()); } void simplifyKnownVariables47() { @@ -2168,6 +2168,7 @@ class TestSimplifyTokens : public TestFixture { "cin >> std :: hex >> x ;\n" "}"; ASSERT_EQUALS(expected, tokenizeAndStringify(code, true, Platform::Type::Native, true)); + ASSERT_EQUALS("[test.cpp:3]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable cin\n", errout_str()); } void simplifyKnownVariables48() { @@ -2197,6 +2198,7 @@ class TestSimplifyTokens : public TestFixture { "}\n" "}"; ASSERT_EQUALS(expected, tokenizeAndStringify(code, true, Platform::Type::Native, false)); + ASSERT_EQUALS("[test.c:2]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable x\n", errout_str()); } void simplifyKnownVariables50() { // #4066 @@ -2219,6 +2221,7 @@ class TestSimplifyTokens : public TestFixture { "return & x7 ;\n" "}"; ASSERT_EQUALS(code, tokenizeAndStringify(code, true)); + ASSERT_EQUALS("[test.cpp:5]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable y\n", errout_str()); } { //don't simplify '&x'! @@ -2239,6 +2242,7 @@ class TestSimplifyTokens : public TestFixture { "return & x7 ;\n" "}"; ASSERT_EQUALS(code, tokenizeAndStringify(code, true)); + ASSERT_EQUALS("[test.cpp:5]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable y\n", errout_str()); } } @@ -2258,6 +2262,7 @@ class TestSimplifyTokens : public TestFixture { void simplifyKnownVariables56() { // ticket #5301 - >> ASSERT_EQUALS("void f ( ) { int a ; a = 0 ; int b ; b = 0 ; * p >> a >> b ; return a / b ; }", tokenizeAndStringify("void f() { int a=0,b=0; *p>>a>>b; return a/b; }", true)); + ASSERT_EQUALS("[test.cpp:1]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable p\n", errout_str()); } void simplifyKnownVariables58() { // #5268 @@ -2337,7 +2342,7 @@ class TestSimplifyTokens : public TestFixture { "return i ;\n" "}"; ASSERT_EQUALS(expected, tokenizeAndStringify(code, true)); - ASSERT_EQUALS("", filter_valueflow(errout_str())); + ASSERT_EQUALS("[test.cpp:3]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable x\n", filter_valueflow(errout_str())); } void simplifyKnownVariablesBailOutAssign2() { @@ -2351,6 +2356,7 @@ class TestSimplifyTokens : public TestFixture { "nr = ( last = list . prev ) . nr ;\n" "}"; ASSERT_EQUALS(expected, tokenizeAndStringify(code, true)); + ASSERT_EQUALS("[test.cpp:3]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable nr\n", errout_str()); } void simplifyKnownVariablesBailOutFor1() { @@ -2411,7 +2417,7 @@ class TestSimplifyTokens : public TestFixture { " return a;\n" "}\n"; tokenizeAndStringify(code,true); - ASSERT_EQUALS("", filter_valueflow(errout_str())); // no debug warnings + ASSERT_EQUALS("[test.cpp:3]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable x\n", filter_valueflow(errout_str())); // no debug warnings } void simplifyKnownVariablesBailOutSwitchBreak() { diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index 4f3fc5e47d3..ddb1fbb4718 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -238,7 +238,7 @@ class TestSimplifyTypedef : public TestFixture { #define tok(...) tok_(__FILE__, __LINE__, __VA_ARGS__) std::string tok_(const char* file, int line, const char code[], bool simplify = true, Platform::Type type = Platform::Type::Native, bool debugwarnings = true) { // show warnings about unhandled typedef - const Settings settings = settingsBuilder(settings0).exhaustive().certainty(Certainty::inconclusive).debugwarnings(debugwarnings).platform(type).build(); + const Settings settings = settingsBuilder(settings0).certainty(Certainty::inconclusive).debugwarnings(debugwarnings).platform(type).build(); SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); diff --git a/test/testsimplifyusing.cpp b/test/testsimplifyusing.cpp index fbeb0c8de15..dd89c87eef9 100644 --- a/test/testsimplifyusing.cpp +++ b/test/testsimplifyusing.cpp @@ -737,7 +737,7 @@ class TestSimplifyUsing : public TestFixture { "cout << std :: string ( c ) << \"abc\" ; " "}"; ASSERT_EQUALS(expected, tok(code, Platform::Type::Native, /*debugwarnings*/ true)); - ASSERT_EQUALS("", errout_str()); + ASSERT_EQUALS("[test.cpp:3]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable cout\n", errout_str()); } { const char code[] = "class T : private std::vector> {\n" // #12521 @@ -853,6 +853,9 @@ class TestSimplifyUsing : public TestFixture { "}"; ASSERT_EQUALS(exp, tok(code)); + ASSERT_EQUALS("[test.cpp:7]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable NS1\n" + "[test.cpp:11]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable NS2\n", + errout_str()); } void simplifyUsing9381() { diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 3b66387caff..d56db42fef9 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -2580,7 +2580,7 @@ class TestSymbolDatabase : public TestFixture { #define check(...) check_(__FILE__, __LINE__, __VA_ARGS__) void check_(const char* file, int line, const char code[], bool debug = true, bool cpp = true, const Settings* pSettings = nullptr) { // Check.. - const Settings settings = settingsBuilder(pSettings ? *pSettings : settings1).debugwarnings(debug).exhaustive().build(); + const Settings settings = settingsBuilder(pSettings ? *pSettings : settings1).debugwarnings(debug).build(); // Tokenize.. SimpleTokenizer tokenizer(settings, *this); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 4f4ac10d249..a2d75652e8c 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -501,6 +501,7 @@ class TestTokenizer : public TestFixture { const char code[] = "void f ( )\n" "{ if ( p . y ( ) > yof ) { } }"; ASSERT_EQUALS(code, tokenizeAndStringify(code)); + ASSERT_EQUALS("[test.cpp:2]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable yof\n", errout_str()); } void tokenize2() { @@ -797,44 +798,44 @@ class TestTokenizer : public TestFixture { } void syntax_case_default() { // correct syntax - tokenizeAndStringify("void f() {switch (n) { case 0: z(); break;}}"); + tokenizeAndStringify("void f(int n) {switch (n) { case 0: z(); break;}}"); ASSERT_EQUALS("", errout_str()); - tokenizeAndStringify("void f() {switch (n) { case 0:; break;}}"); + tokenizeAndStringify("void f(int n) {switch (n) { case 0:; break;}}"); ASSERT_EQUALS("", errout_str()); // TODO: Do not throw AST validation exception - TODO_ASSERT_THROW(tokenizeAndStringify("void f() {switch (n) { case 0?1:2 : z(); break;}}"), InternalError); + TODO_ASSERT_THROW(tokenizeAndStringify("void f(int n) {switch (n) { case 0?1:2 : z(); break;}}"), InternalError); //ASSERT_EQUALS("", errout_str()); // TODO: Do not throw AST validation exception - TODO_ASSERT_THROW(tokenizeAndStringify("void f() {switch (n) { case 0?(1?3:4):2 : z(); break;}}"), InternalError); + TODO_ASSERT_THROW(tokenizeAndStringify("void f(int n) {switch (n) { case 0?(1?3:4):2 : z(); break;}}"), InternalError); ASSERT_EQUALS("", errout_str()); //allow GCC '({ %name%|%num%|%bool% ; })' statement expression extension // TODO: Do not throw AST validation exception - TODO_ASSERT_THROW(tokenizeAndStringify("void f() {switch (n) { case 0?({0;}):1: z(); break;}}"), InternalError); + TODO_ASSERT_THROW(tokenizeAndStringify("void f(int n) {switch (n) { case 0?({0;}):1: z(); break;}}"), InternalError); ASSERT_EQUALS("", errout_str()); //'b' can be or a macro or an undefined enum - tokenizeAndStringify("void f() {switch (n) { case b: z(); break;}}"); + tokenizeAndStringify("void f(int n) {switch (n) { case b: z(); break;}}"); ASSERT_EQUALS("", errout_str()); //valid, when there's this declaration: 'constexpr int g() { return 2; }' - tokenizeAndStringify("void f() {switch (n) { case g(): z(); break;}}"); + tokenizeAndStringify("void f(int n) {switch (n) { case g(): z(); break;}}"); ASSERT_EQUALS("", errout_str()); //valid, when there's also this declaration: 'constexpr int g[1] = {0};' - tokenizeAndStringify("void f() {switch (n) { case g[0]: z(); break;}}"); - ASSERT_EQUALS("", errout_str()); + tokenizeAndStringify("void f(int n) {switch (n) { case g[0]: z(); break;}}"); + ASSERT_EQUALS("[test.cpp:1]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable g\n", errout_str()); //valid, similar to above case - tokenizeAndStringify("void f() {switch (n) { case *g: z(); break;}}"); + tokenizeAndStringify("void f(int n) {switch (n) { case *g: z(); break;}}"); ASSERT_EQUALS("", errout_str()); //valid, when 'x' and 'y' are constexpr. - tokenizeAndStringify("void f() {switch (n) { case sqrt(x+y): z(); break;}}"); - ASSERT_EQUALS("", errout_str()); + tokenizeAndStringify("void f(int n) {switch (n) { case sqrt(x+y): z(); break;}}"); + ASSERT_EQUALS("[test.cpp:1]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable x\n", errout_str()); } void removePragma() { @@ -854,11 +855,12 @@ class TestTokenizer : public TestFixture { // #3690,#5154 const char code[] ="void f() { for each ( char c in MyString ) { Console::Write(c); } }"; ASSERT_EQUALS("void f ( ) { asm ( \"char c in MyString\" ) { Console :: Write ( c ) ; } }", tokenizeAndStringify(code)); + ASSERT_EQUALS("[test.cpp:1]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable c\n", errout_str()); } void ifconstexpr() { ASSERT_EQUALS("void f ( ) { if ( FOO ) { bar ( c ) ; } }", tokenizeAndStringify("void f() { if constexpr ( FOO ) { bar(c); } }")); - ASSERT_EQUALS("", filter_valueflow(errout_str())); + ASSERT_EQUALS("[test.cpp:1]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable FOO\n", filter_valueflow(errout_str())); } void combineOperators() { @@ -1023,7 +1025,7 @@ class TestTokenizer : public TestFixture { "if ( a ) { ; }\n" "else { ; }\n" "}", tokenizeAndStringify(code)); - ASSERT_EQUALS("", filter_valueflow(errout_str())); + ASSERT_EQUALS("[test.cpp:3]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable a\n", filter_valueflow(errout_str())); } void ifAddBraces2() { @@ -1035,7 +1037,7 @@ class TestTokenizer : public TestFixture { "{\n" "if ( a ) { if ( b ) { } }\n" "}", tokenizeAndStringify(code)); - ASSERT_EQUALS("", filter_valueflow(errout_str())); + ASSERT_EQUALS("[test.cpp:3]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable a\n", filter_valueflow(errout_str())); } void ifAddBraces3() { @@ -1047,7 +1049,7 @@ class TestTokenizer : public TestFixture { "{\n" "if ( a ) { for ( ; ; ) { } }\n" "}", tokenizeAndStringify(code)); - ASSERT_EQUALS("", filter_valueflow(errout_str())); + ASSERT_EQUALS("[test.cpp:3]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable a\n", filter_valueflow(errout_str())); } void ifAddBraces4() { @@ -1067,7 +1069,7 @@ class TestTokenizer : public TestFixture { "{ } }\n" "return str ;\n" "}", tokenizeAndStringify(code)); - ASSERT_EQUALS("", filter_valueflow(errout_str())); + ASSERT_EQUALS("[test.cpp:4]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable somecondition\n", filter_valueflow(errout_str())); } void ifAddBraces5() { @@ -1154,7 +1156,7 @@ class TestTokenizer : public TestFixture { "}"; ASSERT_EQUALS("void f ( ) { ( void ) ( { if ( * p ) { ( * p ) = x ( ) ; } } ) }", tokenizeAndStringify(code)); - ASSERT_EQUALS("", filter_valueflow(errout_str())); + ASSERT_EQUALS("[test.cpp:1]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable p\n", filter_valueflow(errout_str())); } } @@ -1175,7 +1177,7 @@ class TestTokenizer : public TestFixture { "else {\n" "bar2 ( ) ; }\n" "}", tokenizeAndStringify(code)); - ASSERT_EQUALS("", filter_valueflow(errout_str())); + ASSERT_EQUALS("[test.cpp:3]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable a\n", filter_valueflow(errout_str())); } void ifAddBraces18() { @@ -1207,7 +1209,7 @@ class TestTokenizer : public TestFixture { "else {\n" "bar2 ( ) ; } } }\n" "}", tokenizeAndStringify(code)); - ASSERT_EQUALS("", filter_valueflow(errout_str())); + ASSERT_EQUALS("[test.cpp:3]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable a\n", filter_valueflow(errout_str())); } void ifAddBraces20() { // #5012 - syntax error 'else }' @@ -1402,7 +1404,7 @@ class TestTokenizer : public TestFixture { "do { while ( x ) { f ( ) ; } } while ( y ) ;\n" "}"; ASSERT_EQUALS(result, tokenizeAndStringify(code)); - ASSERT_EQUALS("", filter_valueflow(errout_str())); + ASSERT_EQUALS("[test.cpp:2]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable x\n", filter_valueflow(errout_str())); } } @@ -1461,7 +1463,7 @@ class TestTokenizer : public TestFixture { "else { } }\n" "}"; ASSERT_EQUALS(expected, tokenizeAndStringify(code)); - ASSERT_EQUALS("", filter_valueflow(errout_str())); + ASSERT_EQUALS("[test.cpp:3]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable a\n", filter_valueflow(errout_str())); } { @@ -1478,7 +1480,7 @@ class TestTokenizer : public TestFixture { "else { } } }\n" "}"; ASSERT_EQUALS(expected, tokenizeAndStringify(code)); - ASSERT_EQUALS("", filter_valueflow(errout_str())); + ASSERT_EQUALS("[test.cpp:3]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable a\n", filter_valueflow(errout_str())); } } @@ -1604,7 +1606,7 @@ class TestTokenizer : public TestFixture { " { }" "}"; ASSERT_EQUALS("void foo ( ) { if ( x ) { int x ; } { } }", tokenizeAndStringify(code)); - ASSERT_EQUALS("", filter_valueflow(errout_str())); + ASSERT_EQUALS("[test.cpp:1]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable x\n", filter_valueflow(errout_str())); } } @@ -1677,7 +1679,7 @@ class TestTokenizer : public TestFixture { " comphelper::EmbeddedObjectContainer aCnt( xDestStorage );\n" " { }\n" "}"); - ASSERT_EQUALS("", errout_str()); + ignore_errout(); } void simplifyFunctionTryCatch() { @@ -1718,6 +1720,7 @@ class TestTokenizer : public TestFixture { "}"; ASSERT_EQUALS("void foo ( ) { free ( ( void * ) p ) ; }", tokenizeAndStringify(code)); + ASSERT_EQUALS("[test.cpp:1]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable p\n", errout_str()); } void removeParentheses3() { @@ -1753,6 +1756,7 @@ class TestTokenizer : public TestFixture { " (free(p));" "}"; ASSERT_EQUALS("void foo ( ) { free ( p ) ; }", tokenizeAndStringify(code)); + ASSERT_EQUALS("[test.cpp:1]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable p\n", errout_str()); } void removeParentheses5() { @@ -1763,6 +1767,7 @@ class TestTokenizer : public TestFixture { " (delete p);" "}"; ASSERT_EQUALS("void foo ( ) { delete p ; }", tokenizeAndStringify(code)); + ASSERT_EQUALS("[test.cpp:1]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable p\n", errout_str()); } // Simplify "( delete [] x )" into "delete [] x" @@ -1772,6 +1777,7 @@ class TestTokenizer : public TestFixture { " (delete [] p);" "}"; ASSERT_EQUALS("void foo ( ) { delete [ ] p ; }", tokenizeAndStringify(code)); + ASSERT_EQUALS("[test.cpp:1]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable p\n", errout_str()); } } @@ -2059,6 +2065,7 @@ class TestTokenizer : public TestFixture { "}", tokenizeAndStringify("void foo(int nX) {\n" " int addI = frontPoint == 2 || frontPoint == 1 ? i = 0, 1 : (i = nX - 2, -1);\n" "}")); + ASSERT_EQUALS("[test.cpp:2]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable frontPoint\n", errout_str()); } void vardecl_stl_1() { @@ -2299,6 +2306,7 @@ class TestTokenizer : public TestFixture { " int a = (x < y) ? 1 : 0;\n" "}"; ASSERT_EQUALS("void f ( ) {\nint a ; a = ( x < y ) ? 1 : 0 ;\n}", tokenizeAndStringify(code)); + ASSERT_EQUALS("[test.cpp:2]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable x\n", errout_str()); } void vardecl14() { @@ -2339,6 +2347,7 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS("void f ( ) {\n" "g ( ( double ) v1 * v2 , v3 , v4 ) ;\n" "}", tokenizeAndStringify(code)); + ASSERT_EQUALS("[test.cpp:2]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable v1\n", errout_str()); } void vardecl19() { @@ -2614,6 +2623,7 @@ class TestTokenizer : public TestFixture { "} ;"; ASSERT_EQUALS(out5, tokenizeAndStringify(in5)); + ASSERT_EQUALS("[test.cpp:3]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable pos\n", errout_str()); } { // Ticket #8679 @@ -3589,8 +3599,8 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS("void foo ( int i ) { switch ( i ) { case -1 : ; break ; } }", tokenizeAndStringify("void foo (int i) { switch(i) { case -1: break; } }")); //ticket #3227 - ASSERT_EQUALS("void foo ( ) { switch ( n ) { label : ; case 1 : ; label1 : ; label2 : ; break ; } }", - tokenizeAndStringify("void foo(){ switch (n){ label: case 1: label1: label2: break; }}")); + ASSERT_EQUALS("void foo ( int n ) { switch ( n ) { label : ; case 1 : ; label1 : ; label2 : ; break ; } }", + tokenizeAndStringify("void foo(int n){ switch (n){ label: case 1: label1: label2: break; }}")); //ticket #8345 ASSERT_EQUALS("void foo ( ) { switch ( 0 ) { case 0 : ; default : ; } }", tokenizeAndStringify("void foo () { switch(0) case 0 : default : ; }")); @@ -3669,6 +3679,7 @@ class TestTokenizer : public TestFixture { "( void ) ( xy ( * p ) ( 0 ) ) ;\n" "}"; ASSERT_EQUALS(expected, tokenizeAndStringify(code)); + ASSERT_EQUALS("[test.cpp:2]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable p\n", errout_str()); } void simplifyFunctionPointers4() { @@ -3976,6 +3987,7 @@ class TestTokenizer : public TestFixture { " FFABS ( sprite_delta [ 1 ] [ i ] ) >= INT_MAX >> shift_y ) ;\n" "}"; ASSERT_EQUALS(std::string::npos, tokenizeAndStringify(code).find("> >")); + ASSERT_EQUALS("[test.cpp:2]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable sprite_shift\n", errout_str()); } { const char code[] = "struct S { bool vector; };\n" @@ -4066,6 +4078,8 @@ class TestTokenizer : public TestFixture { " }; " " template class C2 {}; " "}"); + + ignore_errout(); } void cpp0xtemplate5() { // #9154 @@ -4109,6 +4123,7 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS("; int a [ 1 ] = { foo < bar1 , bar2 > ( 123 , 4 ) } ;", tokenizeAndStringify(";int a[]={foo(123,4)};")); ASSERT_EQUALS("; int a [ 2 ] = { b > c ? 1 : 2 , 3 } ;", tokenizeAndStringify(";int a[]={ b>c?1:2,3};")); ASSERT_EQUALS("int main ( ) { int a [ 2 ] = { b < c ? 1 : 2 , 3 } }", tokenizeAndStringify("int main(){int a[]={bemplace_back(y);\n" "}"); + ignore_errout(); ASSERT_NO_THROW(tokenizeAndStringify("void f() {\n" // #10831 " auto g = [](std::function h = []() {}) { };\n" @@ -6430,7 +6451,7 @@ class TestTokenizer : public TestFixture { ASSERT_NO_THROW(tokenizeAndStringify("void f() {\n" // #11379 " auto l = [x = 3](std::string&& v) { };\n" "}\n")); - ASSERT_EQUALS("", errout_str()); + ASSERT_EQUALS("[test.cpp:2]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable x\n", errout_str()); } void astbrackets() { // [] @@ -6942,6 +6963,8 @@ class TestTokenizer : public TestFixture { "std::string f() {\n" " return std::string{ g() + \"abc\" MACRO \"def\" };\n" "}\n", /*expand*/ true, Platform::Type::Native, true), UNKNOWN_MACRO); + + ignore_errout(); } void findGarbageCode() { // Test Tokenizer::findGarbageCode() @@ -7582,6 +7605,7 @@ class TestTokenizer : public TestFixture { " p = &(ref).value;\n" " return result ;\n" "}\n")); + ignore_errout(); } void noCrash5() { // #10603 diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 5bac755589f..0b8b4a962d2 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -42,7 +42,7 @@ class TestValueFlow : public TestFixture { TestValueFlow() : TestFixture("TestValueFlow") {} private: - /*const*/ Settings settings = settingsBuilder().library("std.cfg").exhaustive().build(); + /*const*/ Settings settings = settingsBuilder().library("std.cfg").build(); void run() override { // strcpy, abort cfg @@ -473,7 +473,7 @@ class TestValueFlow : public TestFixture { #define bailout(...) bailout_(__FILE__, __LINE__, __VA_ARGS__) void bailout_(const char* file, int line, const char code[]) { - const Settings s = settingsBuilder().debugwarnings().exhaustive().build(); + const Settings s = settingsBuilder().debugwarnings().build(); std::vector files(1, "test.cpp"); Tokenizer tokenizer(s, this); @@ -6946,7 +6946,7 @@ class TestValueFlow : public TestFixture { void valueFlowSafeFunctionParameterValues() { const char *code; std::list values; - /*const*/ Settings s = settingsBuilder().exhaustive().library("std.cfg").build(); + /*const*/ Settings s = settingsBuilder().library("std.cfg").build(); s.safeChecks.classes = s.safeChecks.externalFunctions = s.safeChecks.internalFunctions = true; code = "short f(short x) {\n" @@ -6997,7 +6997,7 @@ class TestValueFlow : public TestFixture { void valueFlowUnknownFunctionReturn() { const char *code; std::list values; - /*const*/ Settings s = settingsBuilder().exhaustive().library("std.cfg").build(); + /*const*/ Settings s = settingsBuilder().library("std.cfg").build(); s.checkUnknownFunctionReturn.insert("rand"); code = "x = rand();"; From 3d76663712a79ce9f22ac0a96863912e91162192 Mon Sep 17 00:00:00 2001 From: firewave Date: Wed, 3 Apr 2024 12:03:48 +0200 Subject: [PATCH 4/5] made `CheckLevel` a parameter in the setter functions --- cli/cmdlineparser.cpp | 6 +++--- gui/mainwindow.cpp | 6 +++--- lib/importproject.cpp | 6 +++--- lib/settings.cpp | 29 ++++++++++++++--------------- lib/settings.h | 5 ++--- test/fixture.cpp | 9 ++------- test/fixture.h | 4 +--- 7 files changed, 28 insertions(+), 37 deletions(-) diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 5ae6a7a1ac4..03841fb3814 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -312,7 +312,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a mSettings.exename = Path::getCurrentExecutablePath(argv[0]); // default to --check-level=normal from CLI for now - mSettings.setCheckLevelNormal(); + mSettings.setCheckLevel(Settings::CheckLevel::normal); if (argc <= 1) { printHelp(); @@ -473,11 +473,11 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a // Check code exhaustively else if (std::strcmp(argv[i], "--check-level=exhaustive") == 0) - mSettings.setCheckLevelExhaustive(); + mSettings.setCheckLevel(Settings::CheckLevel::exhaustive); // Check code with normal analysis else if (std::strcmp(argv[i], "--check-level=normal") == 0) - mSettings.setCheckLevelNormal(); + mSettings.setCheckLevel(Settings::CheckLevel::normal); // Check library definitions else if (std::strcmp(argv[i], "--check-library") == 0) { diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 2e358a1f0e6..5d79794784c 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -970,7 +970,7 @@ QPair MainWindow::getCppcheckSettings() result.exename = QCoreApplication::applicationFilePath().toStdString(); // default to --check-level=normal for GUI for now - result.setCheckLevelNormal(); + result.setCheckLevel(Settings::CheckLevel::normal); const bool std = tryLoadLibrary(&result.library, "std.cfg"); if (!std) { @@ -1064,9 +1064,9 @@ QPair MainWindow::getCppcheckSettings() result.maxCtuDepth = mProjectFile->getMaxCtuDepth(); result.maxTemplateRecursion = mProjectFile->getMaxTemplateRecursion(); if (mProjectFile->isCheckLevelExhaustive()) - result.setCheckLevelExhaustive(); + result.setCheckLevel(Settings::CheckLevel::exhaustive); else - result.setCheckLevelNormal(); + result.setCheckLevel(Settings::CheckLevel::normal); result.checkHeaders = mProjectFile->getCheckHeaders(); result.checkUnusedTemplates = mProjectFile->getCheckUnusedTemplates(); result.safeChecks.classes = mProjectFile->safeChecks.classes; diff --git a/lib/importproject.cpp b/lib/importproject.cpp index 64c9a6428eb..e6678831512 100644 --- a/lib/importproject.cpp +++ b/lib/importproject.cpp @@ -1126,7 +1126,7 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti Settings temp; // default to --check-level=normal for import for now - temp.setCheckLevelNormal(); + temp.setCheckLevel(Settings::CheckLevel::normal); guiProject.analyzeAllVsConfigs.clear(); @@ -1271,9 +1271,9 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti settings->safeChecks = temp.safeChecks; if (checkLevelExhaustive) - settings->setCheckLevelExhaustive(); + settings->setCheckLevel(Settings::CheckLevel::exhaustive); else - settings->setCheckLevelNormal(); + settings->setCheckLevel(Settings::CheckLevel::normal); return true; } diff --git a/lib/settings.cpp b/lib/settings.cpp index d5e226da64d..1940a07ced3 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -41,7 +41,7 @@ Settings::Settings() { severity.setEnabled(Severity::error, true); certainty.setEnabled(Certainty::normal, true); - setCheckLevelExhaustive(); + setCheckLevel(Settings::CheckLevel::exhaustive); executor = defaultExecutor(); } @@ -268,21 +268,20 @@ void Settings::loadSummaries() Summaries::loadReturn(buildDir, summaryReturn); } - -void Settings::setCheckLevelExhaustive() -{ - // Checking can take a little while. ~ 10 times slower than normal analysis is OK. - checkLevel = CheckLevel::exhaustive; - performanceValueFlowMaxIfCount = -1; - performanceValueFlowMaxSubFunctionArgs = 256; -} - -void Settings::setCheckLevelNormal() +void Settings::setCheckLevel(CheckLevel level) { - // Checking should finish in reasonable time. - checkLevel = CheckLevel::normal; - performanceValueFlowMaxSubFunctionArgs = 8; - performanceValueFlowMaxIfCount = 100; + if (level == CheckLevel::normal) { + // Checking should finish in reasonable time. + checkLevel = level; + performanceValueFlowMaxSubFunctionArgs = 8; + performanceValueFlowMaxIfCount = 100; + } + else if (level == CheckLevel::exhaustive) { + // Checking can take a little while. ~ 10 times slower than normal analysis is OK. + checkLevel = CheckLevel::exhaustive; + performanceValueFlowMaxIfCount = -1; + performanceValueFlowMaxSubFunctionArgs = 256; + } } // TODO: auto generate these tables diff --git a/lib/settings.h b/lib/settings.h index 03bf0b9530c..2d48464429f 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -456,15 +456,14 @@ class CPPCHECKLIB WARN_UNUSED Settings { return jobs == 1; } - void setCheckLevelExhaustive(); - void setCheckLevelNormal(); - enum class CheckLevel { normal, exhaustive }; CheckLevel checkLevel = CheckLevel::exhaustive; + void setCheckLevel(CheckLevel level); + using ExecuteCmdFn = std::function,std::string,std::string&)>; void setMisraRuleTexts(const ExecuteCmdFn& executeCommand); void setMisraRuleTexts(const std::string& data); diff --git a/test/fixture.cpp b/test/fixture.cpp index 024bd004327..a4cb9b98caa 100644 --- a/test/fixture.cpp +++ b/test/fixture.cpp @@ -445,13 +445,8 @@ void TestFixture::setTemplateFormat(const std::string &templateFormat) } } -TestFixture::SettingsBuilder& TestFixture::SettingsBuilder::normal() { - settings.setCheckLevelNormal(); - return *this; -} - -TestFixture::SettingsBuilder& TestFixture::SettingsBuilder::exhaustive() { - settings.setCheckLevelExhaustive(); +TestFixture::SettingsBuilder& TestFixture::SettingsBuilder::checkLevel(Settings::CheckLevel level) { + settings.setCheckLevel(level); return *this; } diff --git a/test/fixture.h b/test/fixture.h index 17e076546de..cef34a2ba3e 100644 --- a/test/fixture.h +++ b/test/fixture.h @@ -208,9 +208,7 @@ class TestFixture : public ErrorLogger { return *this; } - SettingsBuilder& exhaustive(); - - SettingsBuilder& normal(); + SettingsBuilder& checkLevel(Settings::CheckLevel level); SettingsBuilder& library(const char lib[]); From 408dfa2671a67b39dd15ea00d35fd9e1fea0e76b Mon Sep 17 00:00:00 2001 From: firewave Date: Wed, 3 Apr 2024 12:11:36 +0200 Subject: [PATCH 5/5] CmdLineParser: parse `--check-level=` like other options with values --- cli/cmdlineparser.cpp | 20 ++++++++++++++------ test/testcmdlineparser.cpp | 8 ++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 03841fb3814..503d3f7ff32 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -471,13 +471,21 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a else if (std::strcmp(argv[i], "--check-config") == 0) mSettings.checkConfiguration = true; - // Check code exhaustively - else if (std::strcmp(argv[i], "--check-level=exhaustive") == 0) - mSettings.setCheckLevel(Settings::CheckLevel::exhaustive); + // Check level + else if (std::strncmp(argv[i], "--check-level=", 14) == 0) { + Settings::CheckLevel level = Settings::CheckLevel::normal; + const std::string level_s(argv[i] + 14); + if (level_s == "normal") + level = Settings::CheckLevel::normal; + else if (level_s == "exhaustive") + level = Settings::CheckLevel::exhaustive; + else { + mLogger.printError("unknown '--check-level' value '" + level_s + "'."); + return Result::Fail; + } - // Check code with normal analysis - else if (std::strcmp(argv[i], "--check-level=normal") == 0) - mSettings.setCheckLevel(Settings::CheckLevel::normal); + mSettings.setCheckLevel(level); + } // Check library definitions else if (std::strcmp(argv[i], "--check-library") == 0) { diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index a92047363fa..1756f635f93 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -386,6 +386,7 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(checkLevelDefault); TEST_CASE(checkLevelNormal); TEST_CASE(checkLevelExhaustive); + TEST_CASE(checkLevelUnknown); TEST_CASE(ignorepaths1); TEST_CASE(ignorepaths2); @@ -2595,6 +2596,13 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS(256, settings->performanceValueFlowMaxSubFunctionArgs); } + void checkLevelUnknown() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--check-level=default", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("cppcheck: error: unknown '--check-level' value 'default'.\n", logger->str()); + } + void ignorepaths1() { REDIRECT; const char * const argv[] = {"cppcheck", "-isrc", "file.cpp"};