From 0901ba9a7e415c2ef156d7022f4c9ca65042b1dc Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Sat, 12 Aug 2023 12:58:09 -0500 Subject: [PATCH 01/30] Fix 11865: Assert failure in setSymbolic() (#5318) --- lib/valueflow.cpp | 2 ++ test/testvalueflow.cpp | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index b1e7e52a202..85a64f022ac 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -5448,6 +5448,8 @@ static void valueFlowSymbolicOperators(const SymbolDatabase& symboldatabase, con const Token* arg = tok->next()->astOperand2(); if (!arg) continue; + if (arg->exprId() == 0) + continue; ValueFlow::Value c = inferCondition(">=", arg, 0); if (!c.isKnown()) continue; diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 8a50059ef89..d9faba92820 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -7354,6 +7354,11 @@ class TestValueFlow : public TestFixture { " }\n" "}\n"; valueOfTok(code, "i"); + + code = "void f() {\n" + " if (llabs(0x80000000ffffffffL) == 0x7fffffff00000001L) {}\n" + "}\n"; + valueOfTok(code, "f"); } void valueFlowCrashConstructorInitialization() { // #9577 From 2b3dec4418de72bf4cf69c13d07808d06c9ec13e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Sat, 12 Aug 2023 21:43:12 +0200 Subject: [PATCH 02/30] TestCmdlineParser: properly reset settings and parser between tests (#5310) --- test/fixture.cpp | 2 + test/fixture.h | 1 + test/testcmdlineparser.cpp | 1267 ++++++++++++++++++------------------ 3 files changed, 628 insertions(+), 642 deletions(-) diff --git a/test/fixture.cpp b/test/fixture.cpp index e332fbf7aaf..1eb9d5936a5 100644 --- a/test/fixture.cpp +++ b/test/fixture.cpp @@ -91,6 +91,8 @@ bool TestFixture::prepareTest(const char testname[]) mTemplateFormat.clear(); mTemplateLocation.clear(); + prepareTestInternal(); + // Check if tests should be executed if (testToRun.empty() || testToRun == testname) { // Tests will be executed - prepare them diff --git a/test/fixture.h b/test/fixture.h index a09a193f0e6..f641f09bdee 100644 --- a/test/fixture.h +++ b/test/fixture.h @@ -60,6 +60,7 @@ class TestFixture : public ErrorLogger { virtual void run() = 0; bool prepareTest(const char testname[]); + virtual void prepareTestInternal() {} std::string getLocationStr(const char * const filename, const unsigned int linenr) const; bool assert_(const char * const filename, const unsigned int linenr, const bool condition) const; diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index 455f1e50c6c..ca91e7c3c02 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -51,8 +51,13 @@ class TestCmdlineParser : public TestFixture { } private: - Settings settings; // TODO: reset after each test - CmdLineParser defParser{settings, settings.nomsg, settings.nofail}; // TODO: reset after each test + std::unique_ptr settings; + std::unique_ptr parser; + + void prepareTestInternal() override { + settings.reset(new Settings()); + parser.reset(new CmdLineParser(*settings, settings->nomsg, settings->nofail)); + } void run() override { TEST_CASE(nooptions); @@ -68,7 +73,10 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(debugwarnings); TEST_CASE(forceshort); TEST_CASE(forcelong); - TEST_CASE(relativePaths); + TEST_CASE(relativePaths1); + TEST_CASE(relativePaths2); + TEST_CASE(relativePaths3); + TEST_CASE(relativePaths4); TEST_CASE(quietshort); TEST_CASE(quietlong); TEST_CASE(defines_noarg); @@ -78,7 +86,13 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(defines2); TEST_CASE(defines3); TEST_CASE(defines4); - TEST_CASE(enforceLanguage); + TEST_CASE(enforceLanguage1); + TEST_CASE(enforceLanguage2); + TEST_CASE(enforceLanguage3); + TEST_CASE(enforceLanguage4); + TEST_CASE(enforceLanguage5); + TEST_CASE(enforceLanguage6); + TEST_CASE(enforceLanguage7); TEST_CASE(includesnopath); TEST_CASE(includes); TEST_CASE(includesslash); @@ -135,7 +149,8 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(reportProgressTest); // "Test" suffix to avoid hiding the parent's reportProgress TEST_CASE(stdc99); TEST_CASE(stdcpp11); - TEST_CASE(stdunknown); + TEST_CASE(stdunknown1); + TEST_CASE(stdunknown2); TEST_CASE(platformWin64); TEST_CASE(platformWin32A); TEST_CASE(platformWin32W); @@ -155,7 +170,9 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(plistDoesNotExist); TEST_CASE(suppressionsOld); TEST_CASE(suppressions); - TEST_CASE(suppressionsNoFile); + TEST_CASE(suppressionsNoFile1); + TEST_CASE(suppressionsNoFile2); + TEST_CASE(suppressionsNoFile3); TEST_CASE(suppressionSingle); TEST_CASE(suppressionSingleFile); TEST_CASE(suppressionTwo); @@ -247,179 +264,175 @@ class TestCmdlineParser : public TestFixture { void nooptions() { REDIRECT; const char * const argv[] = {"cppcheck"}; - CmdLineParser parser(settings, settings.nomsg, settings.nofail); - ASSERT(parser.parseFromArgs(1, argv)); - ASSERT_EQUALS(true, parser.getShowHelp()); + ASSERT(parser->parseFromArgs(1, argv)); + ASSERT_EQUALS(true, parser->getShowHelp()); ASSERT(GET_REDIRECT_OUTPUT.find("Cppcheck - A tool for static C/C++ code analysis") == 0); } void helpshort() { REDIRECT; const char * const argv[] = {"cppcheck", "-h"}; - CmdLineParser parser(settings, settings.nomsg, settings.nofail); - ASSERT(parser.parseFromArgs(2, argv)); - ASSERT_EQUALS(true, parser.getShowHelp()); + ASSERT(parser->parseFromArgs(2, argv)); + ASSERT_EQUALS(true, parser->getShowHelp()); ASSERT(GET_REDIRECT_OUTPUT.find("Cppcheck - A tool for static C/C++ code analysis") == 0); } void helplong() { REDIRECT; const char * const argv[] = {"cppcheck", "--help"}; - CmdLineParser parser(settings, settings.nomsg, settings.nofail); - ASSERT(parser.parseFromArgs(2, argv)); - ASSERT_EQUALS(true, parser.getShowHelp()); + ASSERT(parser->parseFromArgs(2, argv)); + ASSERT_EQUALS(true, parser->getShowHelp()); ASSERT(GET_REDIRECT_OUTPUT.find("Cppcheck - A tool for static C/C++ code analysis") == 0); } void showversion() { REDIRECT; const char * const argv[] = {"cppcheck", "--version"}; - CmdLineParser parser(settings, settings.nomsg, settings.nofail); - ASSERT(parser.parseFromArgs(2, argv)); - ASSERT_EQUALS(true, parser.getShowVersion()); + ASSERT(parser->parseFromArgs(2, argv)); + ASSERT_EQUALS(true, parser->getShowVersion()); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); // version is not actually shown } void onefile() { REDIRECT; const char * const argv[] = {"cppcheck", "file.cpp"}; - CmdLineParser parser(settings, settings.nomsg, settings.nofail); - ASSERT(parser.parseFromArgs(2, argv)); - ASSERT_EQUALS(1, (int)parser.getPathNames().size()); - ASSERT_EQUALS("file.cpp", parser.getPathNames().at(0)); + ASSERT(parser->parseFromArgs(2, argv)); + ASSERT_EQUALS(1, (int)parser->getPathNames().size()); + ASSERT_EQUALS("file.cpp", parser->getPathNames().at(0)); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void onepath() { REDIRECT; const char * const argv[] = {"cppcheck", "src"}; - CmdLineParser parser(settings, settings.nomsg, settings.nofail); - ASSERT(parser.parseFromArgs(2, argv)); - ASSERT_EQUALS(1, (int)parser.getPathNames().size()); - ASSERT_EQUALS("src", parser.getPathNames().at(0)); + ASSERT(parser->parseFromArgs(2, argv)); + ASSERT_EQUALS(1, (int)parser->getPathNames().size()); + ASSERT_EQUALS("src", parser->getPathNames().at(0)); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void optionwithoutfile() { REDIRECT; const char * const argv[] = {"cppcheck", "-v"}; - CmdLineParser parser(settings, settings.nomsg, settings.nofail); - ASSERT_EQUALS(false, parser.parseFromArgs(2, argv)); - ASSERT_EQUALS(0, (int)parser.getPathNames().size()); + ASSERT_EQUALS(false, parser->parseFromArgs(2, argv)); + ASSERT_EQUALS(0, (int)parser->getPathNames().size()); ASSERT_EQUALS("cppcheck: error: no C or C++ source files found.\n", GET_REDIRECT_OUTPUT); } void verboseshort() { REDIRECT; const char * const argv[] = {"cppcheck", "-v", "file.cpp"}; - settings.verbose = false; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(true, settings.verbose); + settings->verbose = false; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(true, settings->verbose); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void verboselong() { REDIRECT; const char * const argv[] = {"cppcheck", "--verbose", "file.cpp"}; - settings.verbose = false; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(true, settings.verbose); + settings->verbose = false; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(true, settings->verbose); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void debugSimplified() { REDIRECT; const char * const argv[] = {"cppcheck", "--debug-simplified", "file.cpp"}; - settings.debugSimplified = false; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(true, settings.debugSimplified); + settings->debugSimplified = false; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(true, settings->debugSimplified); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void debugwarnings() { REDIRECT; const char * const argv[] = {"cppcheck", "--debug-warnings", "file.cpp"}; - settings.debugwarnings = false; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(true, settings.debugwarnings); + settings->debugwarnings = false; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(true, settings->debugwarnings); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void forceshort() { REDIRECT; const char * const argv[] = {"cppcheck", "-f", "file.cpp"}; - settings.force = false; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(true, settings.force); + settings->force = false; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(true, settings->force); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void forcelong() { REDIRECT; const char * const argv[] = {"cppcheck", "--force", "file.cpp"}; - settings.force = false; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(true, settings.force); + settings->force = false; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(true, settings->force); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } - void relativePaths() { + void relativePaths1() { REDIRECT; - settings.relativePaths = false; - - const char * const argvs[] = {"cppcheck", "-rp", "file.cpp"}; - ASSERT(defParser.parseFromArgs(3, argvs)); - ASSERT_EQUALS(true, settings.relativePaths); + settings->relativePaths = false; + const char * const argv[] = {"cppcheck", "-rp", "file.cpp"}; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(true, settings->relativePaths); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); + } - CLEAR_REDIRECT_OUTPUT; - settings.relativePaths = false; - - const char * const argvl[] = {"cppcheck", "--relative-paths", "file.cpp"}; - ASSERT(defParser.parseFromArgs(3, argvl)); - ASSERT_EQUALS(true, settings.relativePaths); + void relativePaths2() { + REDIRECT; + settings->relativePaths = false; + const char * const argv[] = {"cppcheck", "--relative-paths", "file.cpp"}; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(true, settings->relativePaths); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); + } - CLEAR_REDIRECT_OUTPUT; - settings.relativePaths = false; - settings.basePaths.clear(); - - const char * const argvsp[] = {"cppcheck", "-rp=C:/foo;C:\\bar", "file.cpp"}; - ASSERT(defParser.parseFromArgs(3, argvsp)); - ASSERT_EQUALS(true, settings.relativePaths); - ASSERT_EQUALS(2, settings.basePaths.size()); - ASSERT_EQUALS("C:/foo", settings.basePaths[0]); - ASSERT_EQUALS("C:/bar", settings.basePaths[1]); + void relativePaths3() { + REDIRECT; + settings->relativePaths = false; + settings->basePaths.clear(); + const char * const argv[] = {"cppcheck", "-rp=C:/foo;C:\\bar", "file.cpp"}; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(true, settings->relativePaths); + ASSERT_EQUALS(2, settings->basePaths.size()); + ASSERT_EQUALS("C:/foo", settings->basePaths[0]); + ASSERT_EQUALS("C:/bar", settings->basePaths[1]); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); + } - CLEAR_REDIRECT_OUTPUT; - settings.relativePaths = false; - settings.basePaths.clear(); + void relativePaths4() { + REDIRECT; + settings->relativePaths = false; + settings->basePaths.clear(); - const char * const argvlp[] = {"cppcheck", "--relative-paths=C:/foo;C:\\bar", "file.cpp"}; - ASSERT(defParser.parseFromArgs(3, argvlp)); - ASSERT_EQUALS(true, settings.relativePaths); - ASSERT_EQUALS(2, settings.basePaths.size()); - ASSERT_EQUALS("C:/foo", settings.basePaths[0]); - ASSERT_EQUALS("C:/bar", settings.basePaths[1]); + const char * const argv[] = {"cppcheck", "--relative-paths=C:/foo;C:\\bar", "file.cpp"}; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(true, settings->relativePaths); + ASSERT_EQUALS(2, settings->basePaths.size()); + ASSERT_EQUALS("C:/foo", settings->basePaths[0]); + ASSERT_EQUALS("C:/bar", settings->basePaths[1]); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void quietshort() { REDIRECT; const char * const argv[] = {"cppcheck", "-q", "file.cpp"}; - settings.quiet = false; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(true, settings.quiet); + settings->quiet = false; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(true, settings->quiet); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void quietlong() { REDIRECT; const char * const argv[] = {"cppcheck", "--quiet", "file.cpp"}; - settings.quiet = false; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(true, settings.quiet); + settings->quiet = false; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(true, settings->quiet); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } @@ -427,7 +440,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "-D"}; // Fails since -D has no param - ASSERT_EQUALS(false, defParser.parseFromArgs(2, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(2, argv)); ASSERT_EQUALS("cppcheck: error: argument to '-D' is missing.\n", GET_REDIRECT_OUTPUT); } @@ -435,7 +448,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "-D", "-v", "file.cpp"}; // Fails since -D has no param - ASSERT_EQUALS(false, defParser.parseFromArgs(4, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(4, argv)); ASSERT_EQUALS("cppcheck: error: argument to '-D' is missing.\n", GET_REDIRECT_OUTPUT); } @@ -443,151 +456,155 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "-D", "--quiet", "file.cpp"}; // Fails since -D has no param - ASSERT_EQUALS(false, defParser.parseFromArgs(4, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(4, argv)); ASSERT_EQUALS("cppcheck: error: argument to '-D' is missing.\n", GET_REDIRECT_OUTPUT); } void defines() { REDIRECT; const char * const argv[] = {"cppcheck", "-D_WIN32", "file.cpp"}; - settings.userDefines.clear(); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS("_WIN32=1", settings.userDefines); + settings->userDefines.clear(); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("_WIN32=1", settings->userDefines); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void defines2() { REDIRECT; const char * const argv[] = {"cppcheck", "-D_WIN32", "-DNODEBUG", "file.cpp"}; - settings.userDefines.clear(); - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT_EQUALS("_WIN32=1;NODEBUG=1", settings.userDefines); + settings->userDefines.clear(); + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT_EQUALS("_WIN32=1;NODEBUG=1", settings->userDefines); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void defines3() { REDIRECT; const char * const argv[] = {"cppcheck", "-D", "DEBUG", "file.cpp"}; - settings.userDefines.clear(); - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT_EQUALS("DEBUG=1", settings.userDefines); + settings->userDefines.clear(); + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT_EQUALS("DEBUG=1", settings->userDefines); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void defines4() { REDIRECT; const char * const argv[] = {"cppcheck", "-DDEBUG=", "file.cpp"}; // #5137 - defining empty macro - settings.userDefines.clear(); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS("DEBUG=", settings.userDefines); - ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); - } - - void enforceLanguage() { - REDIRECT; - { - const char * const argv[] = {"cppcheck", "file.cpp"}; - settings.enforcedLang = Settings::Language::None; - ASSERT(defParser.parseFromArgs(2, argv)); - ASSERT_EQUALS(Settings::Language::None, settings.enforcedLang); - ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); - } - CLEAR_REDIRECT_OUTPUT; - { - const char * const argv[] = {"cppcheck", "-x", "c++", "file.cpp"}; - settings.enforcedLang = Settings::Language::None; - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT_EQUALS(Settings::Language::CPP, settings.enforcedLang); - ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); - } - CLEAR_REDIRECT_OUTPUT; - { - const char * const argv[] = {"cppcheck", "-x"}; - ASSERT(!defParser.parseFromArgs(2, argv)); - ASSERT_EQUALS("cppcheck: error: no language given to '-x' option.\n", GET_REDIRECT_OUTPUT); - } - CLEAR_REDIRECT_OUTPUT; - { - const char * const argv[] = {"cppcheck", "-x", "--inconclusive", "file.cpp"}; - ASSERT(!defParser.parseFromArgs(4, argv)); - ASSERT_EQUALS("cppcheck: error: no language given to '-x' option.\n", GET_REDIRECT_OUTPUT); - } - CLEAR_REDIRECT_OUTPUT; - { - const char * const argv[] = {"cppcheck", "--language=c++", "file.cpp"}; - settings.enforcedLang = Settings::Language::None; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(Settings::Language::CPP, settings.enforcedLang); - ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); - } - CLEAR_REDIRECT_OUTPUT; - { - const char * const argv[] = {"cppcheck", "--language=c", "file.cpp"}; - settings.enforcedLang = Settings::Language::None; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(Settings::Language::C, settings.enforcedLang); - ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); - } - CLEAR_REDIRECT_OUTPUT; - { - const char * const argv[] = {"cppcheck", "--language=unknownLanguage", "file.cpp"}; - ASSERT(!defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS("cppcheck: error: unknown language 'unknownLanguage' enforced.\n", GET_REDIRECT_OUTPUT); - } + settings->userDefines.clear(); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("DEBUG=", settings->userDefines); + ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); + } + + void enforceLanguage1() { + REDIRECT; + const char * const argv[] = {"cppcheck", "file.cpp"}; + settings->enforcedLang = Settings::Language::None; + ASSERT(parser->parseFromArgs(2, argv)); + ASSERT_EQUALS(Settings::Language::None, settings->enforcedLang); + ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); + } + + void enforceLanguage2() { + REDIRECT; + const char * const argv[] = {"cppcheck", "-x", "c++", "file.cpp"}; + settings->enforcedLang = Settings::Language::None; + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT_EQUALS(Settings::Language::CPP, settings->enforcedLang); + ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); + } + + void enforceLanguage3() { + REDIRECT; + const char * const argv[] = {"cppcheck", "-x"}; + ASSERT(!parser->parseFromArgs(2, argv)); + ASSERT_EQUALS("cppcheck: error: no language given to '-x' option.\n", GET_REDIRECT_OUTPUT); + } + + void enforceLanguage4() { + REDIRECT; + const char * const argv[] = {"cppcheck", "-x", "--inconclusive", "file.cpp"}; + ASSERT(!parser->parseFromArgs(4, argv)); + ASSERT_EQUALS("cppcheck: error: no language given to '-x' option.\n", GET_REDIRECT_OUTPUT); + } + + void enforceLanguage5() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--language=c++", "file.cpp"}; + settings->enforcedLang = Settings::Language::None; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(Settings::Language::CPP, settings->enforcedLang); + ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); + } + + void enforceLanguage6() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--language=c", "file.cpp"}; + settings->enforcedLang = Settings::Language::None; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(Settings::Language::C, settings->enforcedLang); + ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); + } + + void enforceLanguage7() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--language=unknownLanguage", "file.cpp"}; + ASSERT(!parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("cppcheck: error: unknown language 'unknownLanguage' enforced.\n", GET_REDIRECT_OUTPUT); } void includesnopath() { REDIRECT; const char * const argv[] = {"cppcheck", "-I"}; // Fails since -I has no param - ASSERT_EQUALS(false, defParser.parseFromArgs(2, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(2, argv)); ASSERT_EQUALS("cppcheck: error: argument to '-I' is missing.\n", GET_REDIRECT_OUTPUT); } void includes() { REDIRECT; const char * const argv[] = {"cppcheck", "-I", "include", "file.cpp"}; - settings.includePaths.clear(); - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT_EQUALS("include/", settings.includePaths.front()); + settings->includePaths.clear(); + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT_EQUALS("include/", settings->includePaths.front()); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void includesslash() { REDIRECT; const char * const argv[] = {"cppcheck", "-I", "include/", "file.cpp"}; - settings.includePaths.clear(); - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT_EQUALS("include/", settings.includePaths.front()); + settings->includePaths.clear(); + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT_EQUALS("include/", settings->includePaths.front()); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void includesbackslash() { REDIRECT; const char * const argv[] = {"cppcheck", "-I", "include\\", "file.cpp"}; - settings.includePaths.clear(); - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT_EQUALS("include/", settings.includePaths.front()); + settings->includePaths.clear(); + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT_EQUALS("include/", settings->includePaths.front()); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void includesnospace() { REDIRECT; const char * const argv[] = {"cppcheck", "-Iinclude", "file.cpp"}; - settings.includePaths.clear(); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS("include/", settings.includePaths.front()); + settings->includePaths.clear(); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("include/", settings->includePaths.front()); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void includes2() { REDIRECT; const char * const argv[] = {"cppcheck", "-I", "include/", "-I", "framework/", "file.cpp"}; - settings.includePaths.clear(); - ASSERT(defParser.parseFromArgs(6, argv)); - ASSERT_EQUALS("include/", settings.includePaths.front()); - settings.includePaths.pop_front(); - ASSERT_EQUALS("framework/", settings.includePaths.front()); + settings->includePaths.clear(); + ASSERT(parser->parseFromArgs(6, argv)); + ASSERT_EQUALS("include/", settings->includePaths.front()); + settings->includePaths.pop_front(); + ASSERT_EQUALS("framework/", settings->includePaths.front()); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } @@ -595,14 +612,14 @@ class TestCmdlineParser : public TestFixture { void includesFile() { REDIRECT; const char * const argv[] = {"cppcheck", "--includes-file=fileThatDoesNotExist.txt", "file.cpp"}; - TODO_ASSERT_EQUALS(true, false, defParser.parseFromArgs(3, argv)); + TODO_ASSERT_EQUALS(true, false, parser->parseFromArgs(3, argv)); TODO_ASSERT_EQUALS("", "cppcheck: error: unable to open includes file at 'fileThatDoesNotExist.txt'\n", GET_REDIRECT_OUTPUT); } void includesFileNoFile() { REDIRECT; const char * const argv[] = {"cppcheck", "--includes-file=fileThatDoesNotExist.txt", "file.cpp"}; - ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: unable to open includes file at 'fileThatDoesNotExist.txt'\n", GET_REDIRECT_OUTPUT); } @@ -610,8 +627,8 @@ class TestCmdlineParser : public TestFixture { void configExcludesFile() { REDIRECT; const char * const argv[] = {"cppcheck", "--config-excludes-file=fileThatDoesNotExist.txt", "file.cpp"}; - settings.includePaths.clear(); - TODO_ASSERT_EQUALS(true, false, defParser.parseFromArgs(3, argv)); + settings->includePaths.clear(); + TODO_ASSERT_EQUALS(true, false, parser->parseFromArgs(3, argv)); // TODO: add checks TODO_ASSERT_EQUALS("", "cppcheck: error: unable to open config excludes file at 'fileThatDoesNotExist.txt'\n", GET_REDIRECT_OUTPUT); } @@ -619,90 +636,83 @@ class TestCmdlineParser : public TestFixture { void configExcludesFileNoFile() { REDIRECT; const char * const argv[] = {"cppcheck", "--config-excludes-file=fileThatDoesNotExist.txt", "file.cpp"}; - ASSERT_EQUALS( false, defParser.parseFromArgs(3, argv)); + ASSERT_EQUALS( false, parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: unable to open config excludes file at 'fileThatDoesNotExist.txt'\n", GET_REDIRECT_OUTPUT); } void enabledAll() { REDIRECT; const char * const argv[] = {"cppcheck", "--enable=all", "file.cpp"}; - settings = Settings(); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT(settings.severity.isEnabled(Severity::style)); - ASSERT(settings.severity.isEnabled(Severity::warning)); - ASSERT(settings.checks.isEnabled(Checks::unusedFunction)); - ASSERT(settings.checks.isEnabled(Checks::missingInclude)); - ASSERT(!settings.checks.isEnabled(Checks::internalCheck)); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->severity.isEnabled(Severity::style)); + ASSERT(settings->severity.isEnabled(Severity::warning)); + ASSERT(settings->checks.isEnabled(Checks::unusedFunction)); + ASSERT(settings->checks.isEnabled(Checks::missingInclude)); + ASSERT(!settings->checks.isEnabled(Checks::internalCheck)); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void enabledStyle() { REDIRECT; const char * const argv[] = {"cppcheck", "--enable=style", "file.cpp"}; - settings = Settings(); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT(settings.severity.isEnabled(Severity::style)); - ASSERT(settings.severity.isEnabled(Severity::warning)); - ASSERT(settings.severity.isEnabled(Severity::performance)); - ASSERT(settings.severity.isEnabled(Severity::portability)); - ASSERT(!settings.checks.isEnabled(Checks::unusedFunction)); - ASSERT(!settings.checks.isEnabled(Checks::internalCheck)); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->severity.isEnabled(Severity::style)); + ASSERT(settings->severity.isEnabled(Severity::warning)); + ASSERT(settings->severity.isEnabled(Severity::performance)); + ASSERT(settings->severity.isEnabled(Severity::portability)); + ASSERT(!settings->checks.isEnabled(Checks::unusedFunction)); + ASSERT(!settings->checks.isEnabled(Checks::internalCheck)); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void enabledPerformance() { REDIRECT; const char * const argv[] = {"cppcheck", "--enable=performance", "file.cpp"}; - settings = Settings(); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT(!settings.severity.isEnabled(Severity::style)); - ASSERT(!settings.severity.isEnabled(Severity::warning)); - ASSERT(settings.severity.isEnabled(Severity::performance)); - ASSERT(!settings.severity.isEnabled(Severity::portability)); - ASSERT(!settings.checks.isEnabled(Checks::unusedFunction)); - ASSERT(!settings.checks.isEnabled(Checks::missingInclude)); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(!settings->severity.isEnabled(Severity::style)); + ASSERT(!settings->severity.isEnabled(Severity::warning)); + ASSERT(settings->severity.isEnabled(Severity::performance)); + ASSERT(!settings->severity.isEnabled(Severity::portability)); + ASSERT(!settings->checks.isEnabled(Checks::unusedFunction)); + ASSERT(!settings->checks.isEnabled(Checks::missingInclude)); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void enabledPortability() { REDIRECT; const char * const argv[] = {"cppcheck", "--enable=portability", "file.cpp"}; - settings = Settings(); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT(!settings.severity.isEnabled(Severity::style)); - ASSERT(!settings.severity.isEnabled(Severity::warning)); - ASSERT(!settings.severity.isEnabled(Severity::performance)); - ASSERT(settings.severity.isEnabled(Severity::portability)); - ASSERT(!settings.checks.isEnabled(Checks::unusedFunction)); - ASSERT(!settings.checks.isEnabled(Checks::missingInclude)); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(!settings->severity.isEnabled(Severity::style)); + ASSERT(!settings->severity.isEnabled(Severity::warning)); + ASSERT(!settings->severity.isEnabled(Severity::performance)); + ASSERT(settings->severity.isEnabled(Severity::portability)); + ASSERT(!settings->checks.isEnabled(Checks::unusedFunction)); + ASSERT(!settings->checks.isEnabled(Checks::missingInclude)); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void enabledInformation() { REDIRECT; const char * const argv[] = {"cppcheck", "--enable=information", "file.cpp"}; - settings = Settings(); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT(settings.severity.isEnabled(Severity::information)); - ASSERT(settings.checks.isEnabled(Checks::missingInclude)); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->severity.isEnabled(Severity::information)); + ASSERT(settings->checks.isEnabled(Checks::missingInclude)); ASSERT_EQUALS("cppcheck: '--enable=information' will no longer implicitly enable 'missingInclude' starting with 2.16. Please enable it explicitly if you require it.\n", GET_REDIRECT_OUTPUT); } void enabledUnusedFunction() { REDIRECT; const char * const argv[] = {"cppcheck", "--enable=unusedFunction", "file.cpp"}; - settings = Settings(); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT(settings.checks.isEnabled(Checks::unusedFunction)); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->checks.isEnabled(Checks::unusedFunction)); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void enabledMissingInclude() { REDIRECT; const char * const argv[] = {"cppcheck", "--enable=missingInclude", "file.cpp"}; - settings = Settings(); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT(settings.checks.isEnabled(Checks::missingInclude)); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->checks.isEnabled(Checks::missingInclude)); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } @@ -710,9 +720,8 @@ class TestCmdlineParser : public TestFixture { void enabledInternal() { REDIRECT; const char * const argv[] = {"cppcheck", "--enable=internal", "file.cpp"}; - settings = Settings(); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT(settings.checks.isEnabled(Checks::internalCheck)); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->checks.isEnabled(Checks::internalCheck)); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } #endif @@ -720,155 +729,147 @@ class TestCmdlineParser : public TestFixture { void enabledMultiple() { REDIRECT; const char * const argv[] = {"cppcheck", "--enable=missingInclude,portability,warning", "file.cpp"}; - settings = Settings(); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT(!settings.severity.isEnabled(Severity::style)); - ASSERT(settings.severity.isEnabled(Severity::warning)); - ASSERT(!settings.severity.isEnabled(Severity::performance)); - ASSERT(settings.severity.isEnabled(Severity::portability)); - ASSERT(!settings.checks.isEnabled(Checks::unusedFunction)); - ASSERT(settings.checks.isEnabled(Checks::missingInclude)); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(!settings->severity.isEnabled(Severity::style)); + ASSERT(settings->severity.isEnabled(Severity::warning)); + ASSERT(!settings->severity.isEnabled(Severity::performance)); + ASSERT(settings->severity.isEnabled(Severity::portability)); + ASSERT(!settings->checks.isEnabled(Checks::unusedFunction)); + ASSERT(settings->checks.isEnabled(Checks::missingInclude)); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void enabledInvalid() { REDIRECT; const char * const argv[] = {"cppcheck", "--enable=warning,missingIncludeSystem,style", "file.cpp"}; - settings = Settings(); - ASSERT(!defParser.parseFromArgs(3, argv)); + ASSERT(!parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: --enable parameter with the unknown name 'missingIncludeSystem'\n", GET_REDIRECT_OUTPUT); } void enabledError() { REDIRECT; const char * const argv[] = {"cppcheck", "--enable=error", "file.cpp"}; - settings = Settings(); - ASSERT(!defParser.parseFromArgs(3, argv)); + ASSERT(!parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: --enable parameter with the unknown name 'error'\n", GET_REDIRECT_OUTPUT); } void enabledEmpty() { REDIRECT; const char * const argv[] = {"cppcheck", "--enable=", "file.cpp"}; - settings = Settings(); - ASSERT(!defParser.parseFromArgs(3, argv)); + ASSERT(!parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: --enable parameter is empty\n", GET_REDIRECT_OUTPUT); } + void disableAll() { REDIRECT; - const char * const argv[] = {"cppcheck", "--enable=all", "--disable=all"}; - settings.severity.clear(); - settings.checks.clear(); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(true, settings.severity.isEnabled(Severity::error)); - ASSERT_EQUALS(false, settings.severity.isEnabled(Severity::warning)); - ASSERT_EQUALS(false, settings.severity.isEnabled(Severity::style)); - ASSERT_EQUALS(false, settings.severity.isEnabled(Severity::performance)); - ASSERT_EQUALS(false, settings.severity.isEnabled(Severity::portability)); - ASSERT_EQUALS(false, settings.severity.isEnabled(Severity::debug)); - ASSERT_EQUALS(false, settings.checks.isEnabled(Checks::unusedFunction)); - ASSERT_EQUALS(false, settings.checks.isEnabled(Checks::missingInclude)); - ASSERT_EQUALS(false, settings.checks.isEnabled(Checks::internalCheck)); + const char * const argv[] = {"cppcheck", "--enable=all", "--disable=all", "file.cpp"}; + settings->severity.clear(); + settings->checks.clear(); + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT_EQUALS(true, settings->severity.isEnabled(Severity::error)); + ASSERT_EQUALS(false, settings->severity.isEnabled(Severity::warning)); + ASSERT_EQUALS(false, settings->severity.isEnabled(Severity::style)); + ASSERT_EQUALS(false, settings->severity.isEnabled(Severity::performance)); + ASSERT_EQUALS(false, settings->severity.isEnabled(Severity::portability)); + ASSERT_EQUALS(false, settings->severity.isEnabled(Severity::debug)); + ASSERT_EQUALS(false, settings->checks.isEnabled(Checks::unusedFunction)); + ASSERT_EQUALS(false, settings->checks.isEnabled(Checks::missingInclude)); + ASSERT_EQUALS(false, settings->checks.isEnabled(Checks::internalCheck)); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void disableMultiple() { REDIRECT; - const char * const argv[] = {"cppcheck", "--enable=all", "--disable=style", "--disable=unusedFunction"}; - settings.severity.clear(); - settings.checks.clear(); - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT_EQUALS(true, settings.severity.isEnabled(Severity::error)); - ASSERT_EQUALS(true, settings.severity.isEnabled(Severity::warning)); - ASSERT_EQUALS(false, settings.severity.isEnabled(Severity::style)); - ASSERT_EQUALS(true, settings.severity.isEnabled(Severity::performance)); - ASSERT_EQUALS(true, settings.severity.isEnabled(Severity::portability)); - ASSERT_EQUALS(true, settings.severity.isEnabled(Severity::debug)); - ASSERT_EQUALS(false, settings.checks.isEnabled(Checks::unusedFunction)); - ASSERT_EQUALS(true, settings.checks.isEnabled(Checks::missingInclude)); - ASSERT_EQUALS(false, settings.checks.isEnabled(Checks::internalCheck)); + const char * const argv[] = {"cppcheck", "--enable=all", "--disable=style", "--disable=unusedFunction", "file.cpp"}; + settings->severity.clear(); + settings->checks.clear(); + ASSERT(parser->parseFromArgs(5, argv)); + ASSERT_EQUALS(true, settings->severity.isEnabled(Severity::error)); + ASSERT_EQUALS(true, settings->severity.isEnabled(Severity::warning)); + ASSERT_EQUALS(false, settings->severity.isEnabled(Severity::style)); + ASSERT_EQUALS(true, settings->severity.isEnabled(Severity::performance)); + ASSERT_EQUALS(true, settings->severity.isEnabled(Severity::portability)); + ASSERT_EQUALS(true, settings->severity.isEnabled(Severity::debug)); + ASSERT_EQUALS(false, settings->checks.isEnabled(Checks::unusedFunction)); + ASSERT_EQUALS(true, settings->checks.isEnabled(Checks::missingInclude)); + ASSERT_EQUALS(false, settings->checks.isEnabled(Checks::internalCheck)); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } // make sure the implied "style" checks are not added when "--enable=style" is specified void disableStylePartial() { REDIRECT; - const char * const argv[] = {"cppcheck", "--enable=style", "--disable=performance", "--enable=unusedFunction"}; - settings.severity.clear(); - settings.checks.clear(); - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT_EQUALS(true, settings.severity.isEnabled(Severity::error)); - ASSERT_EQUALS(true, settings.severity.isEnabled(Severity::warning)); - ASSERT_EQUALS(true, settings.severity.isEnabled(Severity::style)); - ASSERT_EQUALS(false, settings.severity.isEnabled(Severity::performance)); - ASSERT_EQUALS(true, settings.severity.isEnabled(Severity::portability)); - ASSERT_EQUALS(false, settings.severity.isEnabled(Severity::debug)); - ASSERT_EQUALS(true, settings.checks.isEnabled(Checks::unusedFunction)); - ASSERT_EQUALS(false, settings.checks.isEnabled(Checks::missingInclude)); - ASSERT_EQUALS(false, settings.checks.isEnabled(Checks::internalCheck)); + const char * const argv[] = {"cppcheck", "--enable=style", "--disable=performance", "--enable=unusedFunction", "file.cpp"}; + settings->severity.clear(); + settings->checks.clear(); + ASSERT(parser->parseFromArgs(5, argv)); + ASSERT_EQUALS(true, settings->severity.isEnabled(Severity::error)); + ASSERT_EQUALS(true, settings->severity.isEnabled(Severity::warning)); + ASSERT_EQUALS(true, settings->severity.isEnabled(Severity::style)); + ASSERT_EQUALS(false, settings->severity.isEnabled(Severity::performance)); + ASSERT_EQUALS(true, settings->severity.isEnabled(Severity::portability)); + ASSERT_EQUALS(false, settings->severity.isEnabled(Severity::debug)); + ASSERT_EQUALS(true, settings->checks.isEnabled(Checks::unusedFunction)); + ASSERT_EQUALS(false, settings->checks.isEnabled(Checks::missingInclude)); + ASSERT_EQUALS(false, settings->checks.isEnabled(Checks::internalCheck)); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void disableInformationPartial() { REDIRECT; const char * const argv[] = {"cppcheck", "--enable=information", "--disable=missingInclude", "file.cpp"}; - settings = Settings(); - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT(settings.severity.isEnabled(Severity::information)); - ASSERT(!settings.checks.isEnabled(Checks::missingInclude)); + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT(settings->severity.isEnabled(Severity::information)); + ASSERT(!settings->checks.isEnabled(Checks::missingInclude)); ASSERT_EQUALS("cppcheck: '--enable=information' will no longer implicitly enable 'missingInclude' starting with 2.16. Please enable it explicitly if you require it.\n", GET_REDIRECT_OUTPUT); } void disableInformationPartial2() { REDIRECT; const char * const argv[] = {"cppcheck", "--enable=missingInclude", "--disable=information", "file.cpp"}; - settings = Settings(); - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT(!settings.severity.isEnabled(Severity::information)); - ASSERT(settings.checks.isEnabled(Checks::missingInclude)); + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT(!settings->severity.isEnabled(Severity::information)); + ASSERT(settings->checks.isEnabled(Checks::missingInclude)); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void disableInvalid() { REDIRECT; const char * const argv[] = {"cppcheck", "--disable=leaks", "file.cpp"}; - settings = Settings(); - ASSERT(!defParser.parseFromArgs(3, argv)); + ASSERT(!parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: --disable parameter with the unknown name 'leaks'\n", GET_REDIRECT_OUTPUT); } void disableError() { REDIRECT; const char * const argv[] = {"cppcheck", "--disable=error", "file.cpp"}; - settings = Settings(); - ASSERT(!defParser.parseFromArgs(3, argv)); + ASSERT(!parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: --disable parameter with the unknown name 'error'\n", GET_REDIRECT_OUTPUT); } void disableEmpty() { REDIRECT; const char * const argv[] = {"cppcheck", "--disable=", "file.cpp"}; - settings = Settings(); - ASSERT(!defParser.parseFromArgs(3, argv)); + ASSERT(!parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: --disable parameter is empty\n", GET_REDIRECT_OUTPUT); } void inconclusive() { REDIRECT; - const char * const argv[] = {"cppcheck", "--inconclusive"}; - settings.certainty.clear(); - ASSERT(defParser.parseFromArgs(2, argv)); - ASSERT_EQUALS(true, settings.certainty.isEnabled(Certainty::inconclusive)); + const char * const argv[] = {"cppcheck", "--inconclusive", "file.cpp"}; + settings->certainty.clear(); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(true, settings->certainty.isEnabled(Certainty::inconclusive)); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void errorExitcode() { REDIRECT; const char * const argv[] = {"cppcheck", "--error-exitcode=5", "file.cpp"}; - settings.exitCode = 0; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(5, settings.exitCode); + settings->exitCode = 0; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(5, settings->exitCode); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } @@ -876,7 +877,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--error-exitcode=", "file.cpp"}; // Fails since exit code not given - ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: argument to '--error-exitcode=' is not valid - not an integer.\n", GET_REDIRECT_OUTPUT); } @@ -884,14 +885,14 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--error-exitcode=foo", "file.cpp"}; // Fails since invalid exit code - ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: argument to '--error-exitcode=' is not valid - not an integer.\n", GET_REDIRECT_OUTPUT); } void exitcodeSuppressionsOld() { REDIRECT; const char * const argv[] = {"cppcheck", "--exitcode-suppressions", "suppr.txt", "file.cpp"}; - ASSERT_EQUALS(false, defParser.parseFromArgs(4, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(4, argv)); ASSERT_EQUALS("cppcheck: error: unrecognized command line option: \"--exitcode-suppressions\".\n", GET_REDIRECT_OUTPUT); } @@ -899,14 +900,14 @@ class TestCmdlineParser : public TestFixture { // TODO: Fails since cannot open the file REDIRECT; const char * const argv[] = {"cppcheck", "--exitcode-suppressions=suppr.txt", "file.cpp"}; - TODO_ASSERT_EQUALS(true, false, defParser.parseFromArgs(3, argv)); + TODO_ASSERT_EQUALS(true, false, parser->parseFromArgs(3, argv)); TODO_ASSERT_EQUALS("", "cppcheck: error: couldn't open the file: \"suppr.txt\".\n", GET_REDIRECT_OUTPUT); } void exitcodeSuppressionsNoFile() { REDIRECT; const char * const argv[] = {"cppcheck", "--exitcode-suppressions", "file.cpp"}; - ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: unrecognized command line option: \"--exitcode-suppressions\".\n", GET_REDIRECT_OUTPUT); } @@ -914,16 +915,16 @@ class TestCmdlineParser : public TestFixture { void fileList() { REDIRECT; const char * const argv[] = {"cppcheck", "--file-list=files.txt", "file.cpp"}; - TODO_ASSERT_EQUALS(true, false, defParser.parseFromArgs(3, argv)); + TODO_ASSERT_EQUALS(true, false, parser->parseFromArgs(3, argv)); // TODO: settings are not being reset after each test - //TODO_ASSERT_EQUALS(4, 1, defParser.getPathNames().size()); + //TODO_ASSERT_EQUALS(4, 1, defparser->getPathNames().size()); TODO_ASSERT_EQUALS("", "cppcheck: error: couldn't open the file: \"files.txt\".\n", GET_REDIRECT_OUTPUT); } void fileListNoFile() { REDIRECT; const char * const argv[] = {"cppcheck", "--file-list=files.txt", "file.cpp"}; - ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: couldn't open the file: \"files.txt\".\n", GET_REDIRECT_OUTPUT); } @@ -932,41 +933,41 @@ class TestCmdlineParser : public TestFixture { // files in stdin (_pathnames) is empty REDIRECT; const char * const argv[] = {"cppcheck", "--file-list=-", "file.cpp"}; - TODO_ASSERT_EQUALS(true, false, defParser.parseFromArgs(3, argv)); + TODO_ASSERT_EQUALS(true, false, parser->parseFromArgs(3, argv)); TODO_ASSERT_EQUALS("", "", GET_REDIRECT_OUTPUT); } */ void fileListInvalid() { REDIRECT; const char * const argv[] = {"cppcheck", "--file-list", "files.txt", "file.cpp"}; - ASSERT_EQUALS(false, defParser.parseFromArgs(4, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(4, argv)); ASSERT_EQUALS("cppcheck: error: unrecognized command line option: \"--file-list\".\n", GET_REDIRECT_OUTPUT); } void inlineSuppr() { REDIRECT; const char * const argv[] = {"cppcheck", "--inline-suppr", "file.cpp"}; - settings.inlineSuppressions = false; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT(settings.inlineSuppressions); + settings->inlineSuppressions = false; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->inlineSuppressions); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void jobs() { REDIRECT; const char * const argv[] = {"cppcheck", "-j", "3", "file.cpp"}; - settings.jobs = 0; - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT_EQUALS(3, settings.jobs); + settings->jobs = 0; + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT_EQUALS(3, settings->jobs); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void jobs2() { REDIRECT; const char * const argv[] = {"cppcheck", "-j3", "file.cpp"}; - settings.jobs = 0; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(3, settings.jobs); + settings->jobs = 0; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(3, settings->jobs); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } @@ -974,7 +975,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "-j", "file.cpp"}; // Fails since -j is missing thread count - ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: argument to '-j' is not valid - not an integer.\n", GET_REDIRECT_OUTPUT); } @@ -982,25 +983,25 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "-j", "e", "file.cpp"}; // Fails since invalid count given for -j - ASSERT_EQUALS(false, defParser.parseFromArgs(4, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(4, argv)); ASSERT_EQUALS("cppcheck: error: argument to '-j' is not valid - not an integer.\n", GET_REDIRECT_OUTPUT); } void jobsTooBig() { REDIRECT; const char * const argv[] = {"cppcheck", "-j10001", "file.cpp"}; - ASSERT(!defParser.parseFromArgs(3, argv)); + ASSERT(!parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: argument for '-j' is allowed to be 10000 at max.\n", GET_REDIRECT_OUTPUT); } void maxConfigs() { REDIRECT; const char * const argv[] = {"cppcheck", "-f", "--max-configs=12", "file.cpp"}; - settings.force = false; - settings.maxConfigs = 0; - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT_EQUALS(12, settings.maxConfigs); - ASSERT_EQUALS(false, settings.force); + settings->force = false; + settings->maxConfigs = 0; + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT_EQUALS(12, settings->maxConfigs); + ASSERT_EQUALS(false, settings->force); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } @@ -1008,7 +1009,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--max-configs=", "file.cpp"}; // Fails since --max-configs= is missing limit - ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: argument to '--max-configs=' is not valid - not an integer.\n", GET_REDIRECT_OUTPUT); } @@ -1016,7 +1017,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--max-configs=e", "file.cpp"}; // Fails since invalid count given for --max-configs= - ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: argument to '--max-configs=' is not valid - not an integer.\n", GET_REDIRECT_OUTPUT); } @@ -1024,146 +1025,145 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--max-configs=0", "file.cpp"}; // Fails since limit must be greater than 0 - ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: argument to '--max-configs=' must be greater than 0.\n", GET_REDIRECT_OUTPUT); } void reportProgressTest() { REDIRECT; const char * const argv[] = {"cppcheck", "--report-progress", "file.cpp"}; - settings.reportProgress = false; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT(settings.reportProgress); + settings->reportProgress = false; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->reportProgress); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void stdc99() { REDIRECT; const char * const argv[] = {"cppcheck", "--std=c99", "file.cpp"}; - settings.standards.c = Standards::C89; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT(settings.standards.c == Standards::C99); + settings->standards.c = Standards::C89; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->standards.c == Standards::C99); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void stdcpp11() { REDIRECT; const char * const argv[] = {"cppcheck", "--std=c++11", "file.cpp"}; - settings.standards.cpp = Standards::CPP03; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT(settings.standards.cpp == Standards::CPP11); + settings->standards.cpp = Standards::CPP03; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->standards.cpp == Standards::CPP11); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } - void stdunknown() { + void stdunknown1() { + REDIRECT; + const char *const argv[] = {"cppcheck", "--std=d++11", "file.cpp"}; + ASSERT(!parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("cppcheck: error: unknown --std value 'd++11'\n", GET_REDIRECT_OUTPUT); + } + + void stdunknown2() { REDIRECT; - { - const char *const argv[] = {"cppcheck", "--std=d++11", "file.cpp"}; - ASSERT(!defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS("cppcheck: error: unknown --std value 'd++11'\n", GET_REDIRECT_OUTPUT); - } - CLEAR_REDIRECT_OUTPUT; - { - const char *const argv[] = {"cppcheck", "--std=cplusplus11", "file.cpp"}; - TODO_ASSERT(!defParser.parseFromArgs(3, argv)); - TODO_ASSERT_EQUALS("cppcheck: error: unknown --std value 'cplusplus11'\n", "", GET_REDIRECT_OUTPUT); - } + const char *const argv[] = {"cppcheck", "--std=cplusplus11", "file.cpp"}; + TODO_ASSERT(!parser->parseFromArgs(3, argv)); + TODO_ASSERT_EQUALS("cppcheck: error: unknown --std value 'cplusplus11'\n", "", GET_REDIRECT_OUTPUT); } void platformWin64() { REDIRECT; const char * const argv[] = {"cppcheck", "--platform=win64", "file.cpp"}; - ASSERT(settings.platform.set(cppcheck::Platform::Type::Unspecified)); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(cppcheck::Platform::Type::Win64, settings.platform.type); + ASSERT(settings->platform.set(cppcheck::Platform::Type::Unspecified)); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(cppcheck::Platform::Type::Win64, settings->platform.type); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void platformWin32A() { REDIRECT; const char * const argv[] = {"cppcheck", "--platform=win32A", "file.cpp"}; - ASSERT(settings.platform.set(cppcheck::Platform::Type::Unspecified)); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(cppcheck::Platform::Type::Win32A, settings.platform.type); + ASSERT(settings->platform.set(cppcheck::Platform::Type::Unspecified)); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(cppcheck::Platform::Type::Win32A, settings->platform.type); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void platformWin32W() { REDIRECT; const char * const argv[] = {"cppcheck", "--platform=win32W", "file.cpp"}; - ASSERT(settings.platform.set(cppcheck::Platform::Type::Unspecified)); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(cppcheck::Platform::Type::Win32W, settings.platform.type); + ASSERT(settings->platform.set(cppcheck::Platform::Type::Unspecified)); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(cppcheck::Platform::Type::Win32W, settings->platform.type); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void platformUnix32() { REDIRECT; const char * const argv[] = {"cppcheck", "--platform=unix32", "file.cpp"}; - ASSERT(settings.platform.set(cppcheck::Platform::Type::Unspecified)); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(cppcheck::Platform::Type::Unix32, settings.platform.type); + ASSERT(settings->platform.set(cppcheck::Platform::Type::Unspecified)); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(cppcheck::Platform::Type::Unix32, settings->platform.type); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void platformUnix32Unsigned() { REDIRECT; const char * const argv[] = {"cppcheck", "--platform=unix32-unsigned", "file.cpp"}; - ASSERT(settings.platform.set(cppcheck::Platform::Type::Unspecified)); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(cppcheck::Platform::Type::Unix32, settings.platform.type); + ASSERT(settings->platform.set(cppcheck::Platform::Type::Unspecified)); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(cppcheck::Platform::Type::Unix32, settings->platform.type); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void platformUnix64() { REDIRECT; const char * const argv[] = {"cppcheck", "--platform=unix64", "file.cpp"}; - ASSERT(settings.platform.set(cppcheck::Platform::Type::Unspecified)); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(cppcheck::Platform::Type::Unix64, settings.platform.type); + ASSERT(settings->platform.set(cppcheck::Platform::Type::Unspecified)); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(cppcheck::Platform::Type::Unix64, settings->platform.type); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void platformUnix64Unsigned() { REDIRECT; const char * const argv[] = {"cppcheck", "--platform=unix64-unsigned", "file.cpp"}; - ASSERT(settings.platform.set(cppcheck::Platform::Type::Unspecified)); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(cppcheck::Platform::Type::Unix64, settings.platform.type); + ASSERT(settings->platform.set(cppcheck::Platform::Type::Unspecified)); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(cppcheck::Platform::Type::Unix64, settings->platform.type); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void platformNative() { REDIRECT; const char * const argv[] = {"cppcheck", "--platform=native", "file.cpp"}; - ASSERT(settings.platform.set(cppcheck::Platform::Type::Unspecified)); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(cppcheck::Platform::Type::Native, settings.platform.type); + ASSERT(settings->platform.set(cppcheck::Platform::Type::Unspecified)); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(cppcheck::Platform::Type::Native, settings->platform.type); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void platformUnspecified() { REDIRECT; const char * const argv[] = {"cppcheck", "--platform=unspecified", "file.cpp"}; - ASSERT(settings.platform.set(cppcheck::Platform::Type::Native)); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(cppcheck::Platform::Type::Unspecified, settings.platform.type); + ASSERT(settings->platform.set(cppcheck::Platform::Type::Native)); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(cppcheck::Platform::Type::Unspecified, settings->platform.type); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void platformPlatformFile() { REDIRECT; const char * const argv[] = {"cppcheck", "--platform=avr8", "file.cpp"}; - ASSERT(settings.platform.set(cppcheck::Platform::Type::Unspecified)); - ASSERT_EQUALS(true, defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(cppcheck::Platform::Type::File, settings.platform.type); + ASSERT(settings->platform.set(cppcheck::Platform::Type::Unspecified)); + ASSERT_EQUALS(true, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(cppcheck::Platform::Type::File, settings->platform.type); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void platformUnknown() { REDIRECT; const char * const argv[] = {"cppcheck", "--platform=win128", "file.cpp"}; - ASSERT(!defParser.parseFromArgs(3, argv)); + ASSERT(!parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: unrecognized platform: 'win128'.\n", GET_REDIRECT_OUTPUT); } @@ -1174,13 +1174,12 @@ class TestCmdlineParser : public TestFixture { CmdLineParser::SHOW_DEF_PLATFORM_MSG = true; const char * const argv[] = {"cppcheck", "file.cpp"}; - settings = Settings(); - ASSERT(defParser.parseFromArgs(2, argv)); + ASSERT(parser->parseFromArgs(2, argv)); #if defined(_WIN64) - ASSERT_EQUALS(cppcheck::Platform::Type::Win64, settings.platform.type); + ASSERT_EQUALS(cppcheck::Platform::Type::Win64, settings->platform.type); ASSERT_EQUALS("cppcheck: Windows 64-bit binaries currently default to the 'win64' platform. Starting with Cppcheck 2.13 they will default to 'native' instead. Please specify '--platform=win64' explicitly if you rely on this.\n", GET_REDIRECT_OUTPUT); #elif defined(_WIN32) - ASSERT_EQUALS(cppcheck::Platform::Type::Win32A, settings.platform.type); + ASSERT_EQUALS(cppcheck::Platform::Type::Win32A, settings->platform.type); ASSERT_EQUALS("cppcheck: Windows 32-bit binaries currently default to the 'win32A' platform. Starting with Cppcheck 2.13 they will default to 'native' instead. Please specify '--platform=win32A' explicitly if you rely on this.\n", GET_REDIRECT_OUTPUT); #endif @@ -1193,9 +1192,8 @@ class TestCmdlineParser : public TestFixture { CmdLineParser::SHOW_DEF_PLATFORM_MSG = true; const char * const argv[] = {"cppcheck", "--platform=unix64", "file.cpp"}; - settings = Settings(); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(cppcheck::Platform::Type::Unix64, settings.platform.type); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(cppcheck::Platform::Type::Unix64, settings->platform.type); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); CmdLineParser::SHOW_DEF_PLATFORM_MSG = false; @@ -1205,9 +1203,9 @@ class TestCmdlineParser : public TestFixture { void plistEmpty() { REDIRECT; const char * const argv[] = {"cppcheck", "--plist-output=", "file.cpp"}; - settings.plistOutput = ""; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT(settings.plistOutput == "./"); + settings->plistOutput = ""; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->plistOutput == "./"); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } @@ -1215,7 +1213,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--plist-output=./cppcheck_reports", "file.cpp"}; // Fails since folder pointed by --plist-output= does not exist - ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(3, argv)); // TODO: output contains non-native separator //ASSERT_EQUALS("cppcheck: error: plist folder does not exist: \"cppcheck_reports/\".\n", GET_REDIRECT_OUTPUT); } @@ -1223,7 +1221,7 @@ class TestCmdlineParser : public TestFixture { void suppressionsOld() { REDIRECT; const char * const argv[] = {"cppcheck", "--suppressions", "suppr.txt", "file.cpp"}; - ASSERT(!defParser.parseFromArgs(4, argv)); + ASSERT(!parser->parseFromArgs(4, argv)); ASSERT_EQUALS("cppcheck: error: unrecognized command line option: \"--suppressions\".\n", GET_REDIRECT_OUTPUT); } @@ -1231,31 +1229,29 @@ class TestCmdlineParser : public TestFixture { // TODO: Fails because there is no suppr.txt file! REDIRECT; const char * const argv[] = {"cppcheck", "--suppressions-list=suppr.txt", "file.cpp"}; - TODO_ASSERT_EQUALS(true, false, defParser.parseFromArgs(3, argv)); + TODO_ASSERT_EQUALS(true, false, parser->parseFromArgs(3, argv)); TODO_ASSERT_EQUALS("", "cppcheck: error: couldn't open the file: \"suppr.txt\".\n", GET_REDIRECT_OUTPUT); } - void suppressionsNoFile() { + void suppressionsNoFile1() { REDIRECT; - { - const char * const argv[] = {"cppcheck", "--suppressions-list=", "file.cpp"}; - ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(false, GET_REDIRECT_OUTPUT.find("If you want to pass two files") != std::string::npos); - } + const char * const argv[] = {"cppcheck", "--suppressions-list=", "file.cpp"}; + ASSERT_EQUALS(false, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(false, GET_REDIRECT_OUTPUT.find("If you want to pass two files") != std::string::npos); + } - CLEAR_REDIRECT_OUTPUT; - { - const char * const argv[] = {"cppcheck", "--suppressions-list=a.suppr,b.suppr", "file.cpp"}; - ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(true, GET_REDIRECT_OUTPUT.find("If you want to pass two files") != std::string::npos); - } + void suppressionsNoFile2() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--suppressions-list=a.suppr,b.suppr", "file.cpp"}; + ASSERT_EQUALS(false, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(true, GET_REDIRECT_OUTPUT.find("If you want to pass two files") != std::string::npos); + } - CLEAR_REDIRECT_OUTPUT; - { - const char * const argv[] = {"cppcheck", "--suppressions-list=a.suppr b.suppr", "file.cpp"}; - ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(true, GET_REDIRECT_OUTPUT.find("If you want to pass two files") != std::string::npos); - } + void suppressionsNoFile3() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--suppressions-list=a.suppr b.suppr", "file.cpp"}; + ASSERT_EQUALS(false, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(true, GET_REDIRECT_OUTPUT.find("If you want to pass two files") != std::string::npos); } static Suppressions::ErrorMessage errorMessage(const std::string &errorId, const std::string &fileName, int lineNumber) { @@ -1269,116 +1265,112 @@ class TestCmdlineParser : public TestFixture { void suppressionSingle() { REDIRECT; const char * const argv[] = {"cppcheck", "--suppress=uninitvar", "file.cpp"}; - settings = Settings(); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(true, settings.nomsg.isSuppressed(errorMessage("uninitvar", "file.cpp", 1))); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(true, settings->nomsg.isSuppressed(errorMessage("uninitvar", "file.cpp", 1))); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void suppressionSingleFile() { REDIRECT; const char * const argv[] = {"cppcheck", "--suppress=uninitvar:file.cpp", "file.cpp"}; - settings = Settings(); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(true, settings.nomsg.isSuppressed(errorMessage("uninitvar", "file.cpp", 1U))); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(true, settings->nomsg.isSuppressed(errorMessage("uninitvar", "file.cpp", 1U))); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void suppressionTwo() { REDIRECT; const char * const argv[] = {"cppcheck", "--suppress=uninitvar,noConstructor", "file.cpp"}; - settings = Settings(); - TODO_ASSERT_EQUALS(true, false, defParser.parseFromArgs(3, argv)); - TODO_ASSERT_EQUALS(true, false, settings.nomsg.isSuppressed(errorMessage("uninitvar", "file.cpp", 1U))); - TODO_ASSERT_EQUALS(true, false, settings.nomsg.isSuppressed(errorMessage("noConstructor", "file.cpp", 1U))); + TODO_ASSERT_EQUALS(true, false, parser->parseFromArgs(3, argv)); + TODO_ASSERT_EQUALS(true, false, settings->nomsg.isSuppressed(errorMessage("uninitvar", "file.cpp", 1U))); + TODO_ASSERT_EQUALS(true, false, settings->nomsg.isSuppressed(errorMessage("noConstructor", "file.cpp", 1U))); TODO_ASSERT_EQUALS("", "cppcheck: error: Failed to add suppression. Invalid id \"uninitvar,noConstructor\"\n", GET_REDIRECT_OUTPUT); } void suppressionTwoSeparate() { REDIRECT; const char * const argv[] = {"cppcheck", "--suppress=uninitvar", "--suppress=noConstructor", "file.cpp"}; - settings = Settings(); - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT_EQUALS(true, settings.nomsg.isSuppressed(errorMessage("uninitvar", "file.cpp", 1U))); - ASSERT_EQUALS(true, settings.nomsg.isSuppressed(errorMessage("noConstructor", "file.cpp", 1U))); + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT_EQUALS(true, settings->nomsg.isSuppressed(errorMessage("uninitvar", "file.cpp", 1U))); + ASSERT_EQUALS(true, settings->nomsg.isSuppressed(errorMessage("noConstructor", "file.cpp", 1U))); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void templates() { REDIRECT; const char * const argv[] = {"cppcheck", "--template", "{file}:{line},{severity},{id},{message}", "--template-location={file}:{line}:{column} {info}", "file.cpp"}; - settings.templateFormat.clear(); - settings.templateLocation.clear(); - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT_EQUALS("{file}:{line},{severity},{id},{message}", settings.templateFormat); - ASSERT_EQUALS("{file}:{line}:{column} {info}", settings.templateLocation); + settings->templateFormat.clear(); + settings->templateLocation.clear(); + ASSERT(parser->parseFromArgs(5, argv)); + ASSERT_EQUALS("{file}:{line},{severity},{id},{message}", settings->templateFormat); + ASSERT_EQUALS("{file}:{line}:{column} {info}", settings->templateLocation); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void templatesGcc() { REDIRECT; const char * const argv[] = {"cppcheck", "--template", "gcc", "file.cpp"}; - settings.templateFormat.clear(); - settings.templateLocation.clear(); - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT_EQUALS("{file}:{line}:{column}: warning: {message} [{id}]\n{code}", settings.templateFormat); - ASSERT_EQUALS("{file}:{line}:{column}: note: {info}\n{code}", settings.templateLocation); + settings->templateFormat.clear(); + settings->templateLocation.clear(); + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT_EQUALS("{file}:{line}:{column}: warning: {message} [{id}]\n{code}", settings->templateFormat); + ASSERT_EQUALS("{file}:{line}:{column}: note: {info}\n{code}", settings->templateLocation); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void templatesVs() { REDIRECT; const char * const argv[] = {"cppcheck", "--template", "vs", "file.cpp"}; - settings.templateFormat.clear(); - settings.templateLocation.clear(); - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT_EQUALS("{file}({line}): {severity}: {message}", settings.templateFormat); - ASSERT_EQUALS("", settings.templateLocation); + settings->templateFormat.clear(); + settings->templateLocation.clear(); + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT_EQUALS("{file}({line}): {severity}: {message}", settings->templateFormat); + ASSERT_EQUALS("", settings->templateLocation); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void templatesEdit() { REDIRECT; const char * const argv[] = {"cppcheck", "--template", "edit", "file.cpp"}; - settings.templateFormat.clear(); - settings.templateLocation.clear(); - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT_EQUALS("{file} +{line}: {severity}: {message}", settings.templateFormat); - ASSERT_EQUALS("", settings.templateLocation); + settings->templateFormat.clear(); + settings->templateLocation.clear(); + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT_EQUALS("{file} +{line}: {severity}: {message}", settings->templateFormat); + ASSERT_EQUALS("", settings->templateLocation); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void templatesCppcheck1() { REDIRECT; const char * const argv[] = {"cppcheck", "--template=cppcheck1", "file.cpp"}; - settings.templateFormat.clear(); - settings.templateLocation.clear(); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS("{callstack}: ({severity}{inconclusive:, inconclusive}) {message}", settings.templateFormat); - ASSERT_EQUALS("", settings.templateLocation); + settings->templateFormat.clear(); + settings->templateLocation.clear(); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("{callstack}: ({severity}{inconclusive:, inconclusive}) {message}", settings->templateFormat); + ASSERT_EQUALS("", settings->templateLocation); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void templatesDaca2() { REDIRECT; const char * const argv[] = {"cppcheck", "--template=daca2", "file.cpp"}; - settings.templateFormat.clear(); - settings.templateLocation.clear(); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS("{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]", settings.templateFormat); - ASSERT_EQUALS("{file}:{line}:{column}: note: {info}", settings.templateLocation); - ASSERT_EQUALS(true, settings.daca); + settings->templateFormat.clear(); + settings->templateLocation.clear(); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]", settings->templateFormat); + ASSERT_EQUALS("{file}:{line}:{column}: note: {info}", settings->templateLocation); + ASSERT_EQUALS(true, settings->daca); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void templatesSelfcheck() { REDIRECT; const char * const argv[] = {"cppcheck", "--template=selfcheck", "file.cpp"}; - settings.templateFormat.clear(); - settings.templateLocation.clear(); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS("{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\n{code}", settings.templateFormat); - ASSERT_EQUALS("{file}:{line}:{column}: note: {info}\n{code}", settings.templateLocation); + settings->templateFormat.clear(); + settings->templateLocation.clear(); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\n{code}", settings->templateFormat); + ASSERT_EQUALS("{file}:{line}:{column}: note: {info}\n{code}", settings->templateLocation); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } @@ -1386,119 +1378,119 @@ class TestCmdlineParser : public TestFixture { void templatesNoPlaceholder() { REDIRECT; const char * const argv[] = {"cppcheck", "--template=selfchek", "file.cpp"}; - settings.templateFormat.clear(); - settings.templateLocation.clear(); - TODO_ASSERT(!defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS("selfchek", settings.templateFormat); - ASSERT_EQUALS("", settings.templateLocation); + settings->templateFormat.clear(); + settings->templateLocation.clear(); + TODO_ASSERT(!parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("selfchek", settings->templateFormat); + ASSERT_EQUALS("", settings->templateLocation); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void templateFormatInvalid() { REDIRECT; const char* const argv[] = { "cppcheck", "--template", "--template-location={file}", "file.cpp" }; - ASSERT(!defParser.parseFromArgs(4, argv)); + ASSERT(!parser->parseFromArgs(4, argv)); ASSERT_EQUALS("cppcheck: error: argument to '--template' is missing.\n", GET_REDIRECT_OUTPUT); } // TODO: will not error out as he next option does not start with a "-" void templateFormatInvalid2() { REDIRECT; - settings.templateFormat.clear(); - settings.templateLocation.clear(); + settings->templateFormat.clear(); + settings->templateLocation.clear(); const char* const argv[] = { "cppcheck", "--template", "file.cpp" }; - TODO_ASSERT(!defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS("file.cpp", settings.templateFormat); - ASSERT_EQUALS("", settings.templateLocation); - ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); + ASSERT(!parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("file.cpp", settings->templateFormat); + ASSERT_EQUALS("", settings->templateLocation); + TODO_ASSERT_EQUALS("cppcheck: error: argument to '--template' is missing.\n", "cppcheck: error: no C or C++ source files found.\n", GET_REDIRECT_OUTPUT); } // will use the default // TODO: bail out on empty? void templateFormatEmpty() { REDIRECT; - settings.templateFormat.clear(); - settings.templateLocation.clear(); + settings->templateFormat.clear(); + settings->templateLocation.clear(); const char* const argv[] = { "cppcheck", "--template=", "file.cpp" }; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS("{file}:{line}:{column}: {inconclusive:}{severity}:{inconclusive: inconclusive:} {message} [{id}]\n{code}", settings.templateFormat); - ASSERT_EQUALS("{file}:{line}:{column}: note: {info}\n{code}", settings.templateLocation); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("{file}:{line}:{column}: {inconclusive:}{severity}:{inconclusive: inconclusive:} {message} [{id}]\n{code}", settings->templateFormat); + ASSERT_EQUALS("{file}:{line}:{column}: note: {info}\n{code}", settings->templateLocation); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void templateLocationInvalid() { REDIRECT; const char* const argv[] = { "cppcheck", "--template-location", "--template={file}", "file.cpp" }; - ASSERT(!defParser.parseFromArgs(4, argv)); + ASSERT(!parser->parseFromArgs(4, argv)); ASSERT_EQUALS("cppcheck: error: argument to '--template-location' is missing.\n", GET_REDIRECT_OUTPUT); } // TODO: will not error out as he next option does not start with a "-" void templateLocationInvalid2() { REDIRECT; - settings.templateFormat.clear(); - settings.templateLocation.clear(); + settings->templateFormat.clear(); + settings->templateLocation.clear(); const char* const argv[] = { "cppcheck", "--template-location", "file.cpp" }; - TODO_ASSERT(!defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS("{file}:{line}:{column}: {inconclusive:}{severity}:{inconclusive: inconclusive:} {message} [{id}]\n{code}", settings.templateFormat); - ASSERT_EQUALS("file.cpp", settings.templateLocation); - ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); + ASSERT(!parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("{file}:{line}:{column}: {inconclusive:}{severity}:{inconclusive: inconclusive:} {message} [{id}]\n{code}", settings->templateFormat); + ASSERT_EQUALS("file.cpp", settings->templateLocation); + TODO_ASSERT_EQUALS("", "cppcheck: error: no C or C++ source files found.\n", GET_REDIRECT_OUTPUT); } // will use the default // TODO: bail out on empty? void templateLocationEmpty() { REDIRECT; - settings.templateFormat.clear(); - settings.templateLocation.clear(); + settings->templateFormat.clear(); + settings->templateLocation.clear(); const char* const argv[] = { "cppcheck", "--template-location=", "file.cpp" }; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS("{file}:{line}:{column}: {inconclusive:}{severity}:{inconclusive: inconclusive:} {message} [{id}]\n{code}", settings.templateFormat); - ASSERT_EQUALS("{file}:{line}:{column}: note: {info}\n{code}", settings.templateLocation); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("{file}:{line}:{column}: {inconclusive:}{severity}:{inconclusive: inconclusive:} {message} [{id}]\n{code}", settings->templateFormat); + ASSERT_EQUALS("{file}:{line}:{column}: note: {info}\n{code}", settings->templateLocation); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void xml() { REDIRECT; const char * const argv[] = {"cppcheck", "--xml", "file.cpp"}; - settings.xml_version = 1; - settings.xml = false; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT(settings.xml); - ASSERT_EQUALS(1, settings.xml_version); + settings->xml_version = 1; + settings->xml = false; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->xml); + ASSERT_EQUALS(1, settings->xml_version); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void xmlver2() { REDIRECT; const char * const argv[] = {"cppcheck", "--xml-version=2", "file.cpp"}; - settings.xml_version = 1; - settings.xml = false; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT(settings.xml); - ASSERT_EQUALS(2, settings.xml_version); + settings->xml_version = 1; + settings->xml = false; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->xml); + ASSERT_EQUALS(2, settings->xml_version); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void xmlver2both() { REDIRECT; const char * const argv[] = {"cppcheck", "--xml", "--xml-version=2", "file.cpp"}; - settings.xml_version = 1; - settings.xml = false; - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT(settings.xml); - ASSERT_EQUALS(2, settings.xml_version); + settings->xml_version = 1; + settings->xml = false; + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT(settings->xml); + ASSERT_EQUALS(2, settings->xml_version); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void xmlver2both2() { REDIRECT; const char * const argv[] = {"cppcheck", "--xml-version=2", "--xml", "file.cpp"}; - settings.xml_version = 1; - settings.xml = false; - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT(settings.xml); - ASSERT_EQUALS(2, settings.xml_version); + settings->xml_version = 1; + settings->xml = false; + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT(settings->xml); + ASSERT_EQUALS(2, settings->xml_version); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } @@ -1506,7 +1498,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--xml", "--xml-version=3", "file.cpp"}; // FAils since unknown XML format version - ASSERT_EQUALS(false, defParser.parseFromArgs(4, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(4, argv)); ASSERT_EQUALS("cppcheck: error: '--xml-version' can only be 2.\n", GET_REDIRECT_OUTPUT); } @@ -1514,91 +1506,90 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--xml", "--xml-version=a", "file.cpp"}; // FAils since unknown XML format version - ASSERT_EQUALS(false, defParser.parseFromArgs(4, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(4, argv)); ASSERT_EQUALS("cppcheck: error: argument to '--xml-version=' is not valid - not an integer.\n", GET_REDIRECT_OUTPUT); } void doc() { REDIRECT; const char * const argv[] = {"cppcheck", "--doc"}; - ASSERT(defParser.parseFromArgs(2, argv)); - ASSERT(defParser.exitAfterPrinting()); + ASSERT(parser->parseFromArgs(2, argv)); + ASSERT(parser->exitAfterPrinting()); ASSERT(GET_REDIRECT_OUTPUT.find("## ") == 0); } void showtime() { REDIRECT; - const char * const argv[] = {"cppcheck", "--showtime=summary"}; - settings.showtime = SHOWTIME_MODES::SHOWTIME_NONE; - ASSERT(defParser.parseFromArgs(2, argv)); - ASSERT(settings.showtime == SHOWTIME_MODES::SHOWTIME_SUMMARY); + const char * const argv[] = {"cppcheck", "--showtime=summary", "file.cpp"}; + settings->showtime = SHOWTIME_MODES::SHOWTIME_NONE; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->showtime == SHOWTIME_MODES::SHOWTIME_SUMMARY); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void errorlist1() { REDIRECT; const char * const argv[] = {"cppcheck", "--errorlist"}; - ASSERT(defParser.parseFromArgs(2, argv)); - ASSERT(defParser.getShowErrorMessages()); + ASSERT(parser->parseFromArgs(2, argv)); + ASSERT(parser->getShowErrorMessages()); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void errorlistverbose1() { REDIRECT; const char * const argv[] = {"cppcheck", "--verbose", "--errorlist"}; - settings.verbose = false; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT(settings.verbose); + settings->verbose = false; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->verbose); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void errorlistverbose2() { REDIRECT; const char * const argv[] = {"cppcheck", "--errorlist", "--verbose"}; - settings.verbose = false; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT(settings.verbose); + settings->verbose = false; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->verbose); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void ignorepathsnopath() { REDIRECT; const char * const argv[] = {"cppcheck", "-i"}; - CmdLineParser parser(settings, settings.nomsg, settings.nofail); // Fails since no ignored path given - ASSERT_EQUALS(false, parser.parseFromArgs(2, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(2, argv)); ASSERT_EQUALS("cppcheck: error: argument to '-i' is missing.\n", GET_REDIRECT_OUTPUT); } void exceptionhandling() { REDIRECT; - const char * const argv[] = {"cppcheck", "--exception-handling"}; - settings.exceptionHandling = false; + const char * const argv[] = {"cppcheck", "--exception-handling", "file.cpp"}; + settings->exceptionHandling = false; CppCheckExecutor::setExceptionOutput(stderr); - ASSERT(defParser.parseFromArgs(2, argv)); - ASSERT(settings.exceptionHandling); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->exceptionHandling); ASSERT_EQUALS(stderr, CppCheckExecutor::getExceptionOutput()); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void exceptionhandling2() { REDIRECT; - const char * const argv[] = {"cppcheck", "--exception-handling=stderr"}; - settings.exceptionHandling = false; + const char * const argv[] = {"cppcheck", "--exception-handling=stderr", "file.cpp"}; + settings->exceptionHandling = false; CppCheckExecutor::setExceptionOutput(stdout); - ASSERT(defParser.parseFromArgs(2, argv)); - ASSERT(settings.exceptionHandling); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->exceptionHandling); ASSERT_EQUALS(stderr, CppCheckExecutor::getExceptionOutput()); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void exceptionhandling3() { REDIRECT; - const char * const argv[] = {"cppcheck", "--exception-handling=stdout"}; - settings.exceptionHandling = false; + const char * const argv[] = {"cppcheck", "--exception-handling=stdout", "file.cpp"}; + settings->exceptionHandling = false; CppCheckExecutor::setExceptionOutput(stderr); - ASSERT(defParser.parseFromArgs(2, argv)); - ASSERT(settings.exceptionHandling); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->exceptionHandling); ASSERT_EQUALS(stdout, CppCheckExecutor::getExceptionOutput()); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } @@ -1606,105 +1597,105 @@ class TestCmdlineParser : public TestFixture { void exceptionhandlingInvalid() { REDIRECT; const char * const argv[] = {"cppcheck", "--exception-handling=exfile"}; - ASSERT_EQUALS(false, defParser.parseFromArgs(2, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(2, argv)); ASSERT_EQUALS("cppcheck: error: invalid '--exception-handling' argument\n", GET_REDIRECT_OUTPUT); } void exceptionhandlingInvalid2() { REDIRECT; const char * const argv[] = {"cppcheck", "--exception-handling-foo"}; - ASSERT_EQUALS(false, defParser.parseFromArgs(2, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(2, argv)); ASSERT_EQUALS("cppcheck: error: unrecognized command line option: \"--exception-handling-foo\".\n", GET_REDIRECT_OUTPUT); } void clang() { REDIRECT; - const char * const argv[] = {"cppcheck", "--clang"}; - settings.clang = false; - settings.clangExecutable = "exe"; - ASSERT(defParser.parseFromArgs(2, argv)); - ASSERT(settings.clang); - ASSERT_EQUALS("exe", settings.clangExecutable); + const char * const argv[] = {"cppcheck", "--clang", "file.cpp"}; + settings->clang = false; + settings->clangExecutable = "exe"; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->clang); + ASSERT_EQUALS("exe", settings->clangExecutable); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void clang2() { REDIRECT; - const char * const argv[] = {"cppcheck", "--clang=clang-14"}; - settings.clang = false; - settings.clangExecutable = ""; - ASSERT(defParser.parseFromArgs(2, argv)); - ASSERT(settings.clang); - ASSERT_EQUALS("clang-14", settings.clangExecutable); + const char * const argv[] = {"cppcheck", "--clang=clang-14", "file.cpp"}; + settings->clang = false; + settings->clangExecutable = ""; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT(settings->clang); + ASSERT_EQUALS("clang-14", settings->clangExecutable); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void clangInvalid() { REDIRECT; const char * const argv[] = {"cppcheck", "--clang-foo"}; - ASSERT_EQUALS(false, defParser.parseFromArgs(2, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(2, argv)); ASSERT_EQUALS("cppcheck: error: unrecognized command line option: \"--clang-foo\".\n", GET_REDIRECT_OUTPUT); } void valueFlowMaxIterations() { REDIRECT; - const char * const argv[] = {"cppcheck", "--valueflow-max-iterations=0"}; - settings.valueFlowMaxIterations = SIZE_MAX; - ASSERT(defParser.parseFromArgs(2, argv)); - ASSERT_EQUALS(0, settings.valueFlowMaxIterations); + const char * const argv[] = {"cppcheck", "--valueflow-max-iterations=0", "file.cpp"}; + settings->valueFlowMaxIterations = SIZE_MAX; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(0, settings->valueFlowMaxIterations); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void valueFlowMaxIterations2() { REDIRECT; - const char * const argv[] = {"cppcheck", "--valueflow-max-iterations=11"}; - settings.valueFlowMaxIterations = SIZE_MAX; - ASSERT(defParser.parseFromArgs(2, argv)); - ASSERT_EQUALS(11, settings.valueFlowMaxIterations); + const char * const argv[] = {"cppcheck", "--valueflow-max-iterations=11", "file.cpp"}; + settings->valueFlowMaxIterations = SIZE_MAX; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(11, settings->valueFlowMaxIterations); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void valueFlowMaxIterationsInvalid() { REDIRECT; const char * const argv[] = {"cppcheck", "--valueflow-max-iterations"}; - ASSERT(!defParser.parseFromArgs(2, argv)); + ASSERT(!parser->parseFromArgs(2, argv)); ASSERT_EQUALS("cppcheck: error: unrecognized command line option: \"--valueflow-max-iterations\".\n", GET_REDIRECT_OUTPUT); } void valueFlowMaxIterationsInvalid2() { REDIRECT; const char * const argv[] = {"cppcheck", "--valueflow-max-iterations=seven"}; - ASSERT(!defParser.parseFromArgs(2, argv)); + ASSERT(!parser->parseFromArgs(2, argv)); ASSERT_EQUALS("cppcheck: error: argument to '--valueflow-max-iterations=' is not valid - not an integer.\n", GET_REDIRECT_OUTPUT); } void valueFlowMaxIterationsInvalid3() { REDIRECT; const char * const argv[] = {"cppcheck", "--valueflow-max-iterations=-1"}; - ASSERT(!defParser.parseFromArgs(2, argv)); + ASSERT(!parser->parseFromArgs(2, argv)); ASSERT_EQUALS("cppcheck: error: argument to '--valueflow-max-iterations=' is not valid - needs to be positive.\n", GET_REDIRECT_OUTPUT); } void checksMaxTime() { REDIRECT; const char * const argv[] = {"cppcheck", "--checks-max-time=12", "file.cpp"}; - settings.checksMaxTime = 0; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(12, settings.checksMaxTime); + settings->checksMaxTime = 0; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(12, settings->checksMaxTime); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void checksMaxTime2() { REDIRECT; const char * const argv[] = {"cppcheck", "--checks-max-time=-1", "file.cpp"}; - ASSERT(!defParser.parseFromArgs(3, argv)); + ASSERT(!parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: argument to '--checks-max-time=' needs to be a positive integer.\n", GET_REDIRECT_OUTPUT); } void checksMaxTimeInvalid() { REDIRECT; const char * const argv[] = {"cppcheck", "--checks-max-time=one", "file.cpp"}; - ASSERT(!defParser.parseFromArgs(3, argv)); + ASSERT(!parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: argument to '--checks-max-time=' is not valid - not an integer.\n", GET_REDIRECT_OUTPUT); } @@ -1712,25 +1703,25 @@ class TestCmdlineParser : public TestFixture { void loadAverage() { REDIRECT; const char * const argv[] = {"cppcheck", "-l", "12", "file.cpp"}; - settings.loadAverage = 0; - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT_EQUALS(12, settings.loadAverage); + settings->loadAverage = 0; + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT_EQUALS(12, settings->loadAverage); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void loadAverage2() { REDIRECT; const char * const argv[] = {"cppcheck", "-l12", "file.cpp"}; - settings.loadAverage = 0; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(12, settings.loadAverage); + settings->loadAverage = 0; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(12, settings->loadAverage); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void loadAverageInvalid() { REDIRECT; const char * const argv[] = {"cppcheck", "-l", "one", "file.cpp"}; - ASSERT(!defParser.parseFromArgs(4, argv)); + ASSERT(!parser->parseFromArgs(4, argv)); ASSERT_EQUALS("cppcheck: error: argument to '-l' is not valid - not an integer.\n", GET_REDIRECT_OUTPUT); } #endif @@ -1738,193 +1729,185 @@ class TestCmdlineParser : public TestFixture { void maxCtuDepth() { REDIRECT; const char * const argv[] = {"cppcheck", "--max-ctu-depth=12", "file.cpp"}; - settings.maxCtuDepth = 0; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(12, settings.maxCtuDepth); + settings->maxCtuDepth = 0; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(12, settings->maxCtuDepth); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void maxCtuDepthInvalid() { REDIRECT; const char * const argv[] = {"cppcheck", "--max-ctu-depth=one", "file.cpp"}; - ASSERT(!defParser.parseFromArgs(3, argv)); + ASSERT(!parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: argument to '--max-ctu-depth=' is not valid - not an integer.\n", GET_REDIRECT_OUTPUT); } void performanceValueflowMaxTime() { REDIRECT; const char * const argv[] = {"cppcheck", "--performance-valueflow-max-time=12", "file.cpp"}; - settings.performanceValueFlowMaxTime = 0; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(12, settings.performanceValueFlowMaxTime); + settings->performanceValueFlowMaxTime = 0; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(12, settings->performanceValueFlowMaxTime); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void performanceValueflowMaxTimeInvalid() { REDIRECT; const char * const argv[] = {"cppcheck", "--performance-valueflow-max-time=one", "file.cpp"}; - ASSERT(!defParser.parseFromArgs(3, argv)); + ASSERT(!parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: argument to '--performance-valueflow-max-time=' is not valid - not an integer.\n", GET_REDIRECT_OUTPUT); } void performanceValueFlowMaxIfCount() { REDIRECT; const char * const argv[] = {"cppcheck", "--performance-valueflow-max-if-count=12", "file.cpp"}; - settings.performanceValueFlowMaxIfCount = 0; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(12, settings.performanceValueFlowMaxIfCount); + settings->performanceValueFlowMaxIfCount = 0; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(12, settings->performanceValueFlowMaxIfCount); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void performanceValueFlowMaxIfCountInvalid() { REDIRECT; const char * const argv[] = {"cppcheck", "--performance-valueflow-max-if-count=one", "file.cpp"}; - ASSERT(!defParser.parseFromArgs(3, argv)); + ASSERT(!parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: argument to '--performance-valueflow-max-if-count=' is not valid - not an integer.\n", GET_REDIRECT_OUTPUT); } void templateMaxTime() { REDIRECT; const char * const argv[] = {"cppcheck", "--template-max-time=12", "file.cpp"}; - settings.templateMaxTime = 0; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(12, settings.templateMaxTime); + settings->templateMaxTime = 0; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(12, settings->templateMaxTime); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void templateMaxTimeInvalid() { REDIRECT; const char * const argv[] = {"cppcheck", "--template-max-time=one", "file.cpp"}; - ASSERT(!defParser.parseFromArgs(3, argv)); + ASSERT(!parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: argument to '--template-max-time=' is not valid - not an integer.\n", GET_REDIRECT_OUTPUT); } void templateMaxTimeInvalid2() { REDIRECT; const char * const argv[] = {"cppcheck", "--template-max-time=-1", "file.cpp"}; - ASSERT(!defParser.parseFromArgs(3, argv)); + ASSERT(!parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: argument to '--template-max-time=' is not valid - needs to be positive.\n", GET_REDIRECT_OUTPUT); } void typedefMaxTime() { REDIRECT; const char * const argv[] = {"cppcheck", "--typedef-max-time=12", "file.cpp"}; - settings.typedefMaxTime = 0; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(12, settings.typedefMaxTime); + settings->typedefMaxTime = 0; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(12, settings->typedefMaxTime); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void typedefMaxTimeInvalid() { REDIRECT; const char * const argv[] = {"cppcheck", "--typedef-max-time=one", "file.cpp"}; - ASSERT(!defParser.parseFromArgs(3, argv)); + ASSERT(!parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: argument to '--typedef-max-time=' is not valid - not an integer.\n", GET_REDIRECT_OUTPUT); } void typedefMaxTimeInvalid2() { REDIRECT; const char * const argv[] = {"cppcheck", "--typedef-max-time=-1", "file.cpp"}; - ASSERT(!defParser.parseFromArgs(3, argv)); + ASSERT(!parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: argument to '--typedef-max-time=' is not valid - needs to be positive.\n", GET_REDIRECT_OUTPUT); } void ignorepaths1() { REDIRECT; const char * const argv[] = {"cppcheck", "-isrc", "file.cpp"}; - CmdLineParser parser(settings, settings.nomsg, settings.nofail); - ASSERT(parser.parseFromArgs(3, argv)); - ASSERT_EQUALS(1, parser.getIgnoredPaths().size()); - ASSERT_EQUALS("src", parser.getIgnoredPaths()[0]); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); + ASSERT_EQUALS("src", parser->getIgnoredPaths()[0]); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void ignorepaths2() { REDIRECT; const char * const argv[] = {"cppcheck", "-i", "src", "file.cpp"}; - CmdLineParser parser(settings, settings.nomsg, settings.nofail); - ASSERT(parser.parseFromArgs(4, argv)); - ASSERT_EQUALS(1, parser.getIgnoredPaths().size()); - ASSERT_EQUALS("src", parser.getIgnoredPaths()[0]); + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); + ASSERT_EQUALS("src", parser->getIgnoredPaths()[0]); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void ignorepaths3() { REDIRECT; const char * const argv[] = {"cppcheck", "-isrc", "-imodule", "file.cpp"}; - CmdLineParser parser(settings, settings.nomsg, settings.nofail); - ASSERT(parser.parseFromArgs(4, argv)); - ASSERT_EQUALS(2, parser.getIgnoredPaths().size()); - ASSERT_EQUALS("src", parser.getIgnoredPaths()[0]); - ASSERT_EQUALS("module", parser.getIgnoredPaths()[1]); + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT_EQUALS(2, parser->getIgnoredPaths().size()); + ASSERT_EQUALS("src", parser->getIgnoredPaths()[0]); + ASSERT_EQUALS("module", parser->getIgnoredPaths()[1]); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void ignorepaths4() { REDIRECT; const char * const argv[] = {"cppcheck", "-i", "src", "-i", "module", "file.cpp"}; - CmdLineParser parser(settings, settings.nomsg, settings.nofail); - ASSERT(parser.parseFromArgs(6, argv)); - ASSERT_EQUALS(2, parser.getIgnoredPaths().size()); - ASSERT_EQUALS("src", parser.getIgnoredPaths()[0]); - ASSERT_EQUALS("module", parser.getIgnoredPaths()[1]); + ASSERT(parser->parseFromArgs(6, argv)); + ASSERT_EQUALS(2, parser->getIgnoredPaths().size()); + ASSERT_EQUALS("src", parser->getIgnoredPaths()[0]); + ASSERT_EQUALS("module", parser->getIgnoredPaths()[1]); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void ignorefilepaths1() { REDIRECT; const char * const argv[] = {"cppcheck", "-ifoo.cpp", "file.cpp"}; - CmdLineParser parser(settings, settings.nomsg, settings.nofail); - ASSERT(parser.parseFromArgs(3, argv)); - ASSERT_EQUALS(1, parser.getIgnoredPaths().size()); - ASSERT_EQUALS("foo.cpp", parser.getIgnoredPaths()[0]); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); + ASSERT_EQUALS("foo.cpp", parser->getIgnoredPaths()[0]); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void ignorefilepaths2() { REDIRECT; const char * const argv[] = {"cppcheck", "-isrc/foo.cpp", "file.cpp"}; - CmdLineParser parser(settings, settings.nomsg, settings.nofail); - ASSERT(parser.parseFromArgs(3, argv)); - ASSERT_EQUALS(1, parser.getIgnoredPaths().size()); - ASSERT_EQUALS("src/foo.cpp", parser.getIgnoredPaths()[0]); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); + ASSERT_EQUALS("src/foo.cpp", parser->getIgnoredPaths()[0]); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void checkconfig() { REDIRECT; const char * const argv[] = {"cppcheck", "--check-config", "file.cpp"}; - settings.checkConfiguration = false; - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(true, settings.checkConfiguration); + settings->checkConfiguration = false; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(true, settings->checkConfiguration); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void unknownParam() { REDIRECT; const char * const argv[] = {"cppcheck", "--foo", "file.cpp"}; - ASSERT(!defParser.parseFromArgs(3, argv)); + ASSERT(!parser->parseFromArgs(3, argv)); ASSERT_EQUALS("cppcheck: error: unrecognized command line option: \"--foo\".\n", GET_REDIRECT_OUTPUT); } void undefs() { REDIRECT; const char * const argv[] = {"cppcheck", "-U_WIN32", "file.cpp"}; - settings = Settings(); - ASSERT(defParser.parseFromArgs(3, argv)); - ASSERT_EQUALS(1, settings.userUndefs.size()); - ASSERT(settings.userUndefs.find("_WIN32") != settings.userUndefs.end()); + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(1, settings->userUndefs.size()); + ASSERT(settings->userUndefs.find("_WIN32") != settings->userUndefs.end()); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void undefs2() { REDIRECT; const char * const argv[] = {"cppcheck", "-U_WIN32", "-UNODEBUG", "file.cpp"}; - settings = Settings(); - ASSERT(defParser.parseFromArgs(4, argv)); - ASSERT_EQUALS(2, settings.userUndefs.size()); - ASSERT(settings.userUndefs.find("_WIN32") != settings.userUndefs.end()); - ASSERT(settings.userUndefs.find("NODEBUG") != settings.userUndefs.end()); + ASSERT(parser->parseFromArgs(4, argv)); + ASSERT_EQUALS(2, settings->userUndefs.size()); + ASSERT(settings->userUndefs.find("_WIN32") != settings->userUndefs.end()); + ASSERT(settings->userUndefs.find("NODEBUG") != settings->userUndefs.end()); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } @@ -1932,7 +1915,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "-U"}; // Fails since -U has no param - ASSERT_EQUALS(false, defParser.parseFromArgs(2, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(2, argv)); ASSERT_EQUALS("cppcheck: error: argument to '-U' is missing.\n", GET_REDIRECT_OUTPUT); } @@ -1940,7 +1923,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "-U", "-v", "file.cpp"}; // Fails since -U has no param - ASSERT_EQUALS(false, defParser.parseFromArgs(4, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(4, argv)); ASSERT_EQUALS("cppcheck: error: argument to '-U' is missing.\n", GET_REDIRECT_OUTPUT); } @@ -1948,28 +1931,28 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "-U", "--quiet", "file.cpp"}; // Fails since -U has no param - ASSERT_EQUALS(false, defParser.parseFromArgs(4, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(4, argv)); ASSERT_EQUALS("cppcheck: error: argument to '-U' is missing.\n", GET_REDIRECT_OUTPUT); } void cppcheckBuildDirExistent() { REDIRECT; - const char * const argv[] = {"cppcheck", "--cppcheck-build-dir=."}; - ASSERT_EQUALS(true, defParser.parseFromArgs(2, argv)); + const char * const argv[] = {"cppcheck", "--cppcheck-build-dir=.", "file.cpp"}; + ASSERT_EQUALS(true, parser->parseFromArgs(3, argv)); ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void cppcheckBuildDirNonExistent() { REDIRECT; const char * const argv[] = {"cppcheck", "--cppcheck-build-dir=non-existent-path"}; - ASSERT_EQUALS(false, defParser.parseFromArgs(2, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(2, argv)); ASSERT_EQUALS("cppcheck: error: Directory 'non-existent-path' specified by --cppcheck-build-dir argument has to be existent.\n", GET_REDIRECT_OUTPUT); } void cppcheckBuildDirEmpty() { REDIRECT; const char * const argv[] = {"cppcheck", "--cppcheck-build-dir="}; - ASSERT_EQUALS(false, defParser.parseFromArgs(2, argv)); + ASSERT_EQUALS(false, parser->parseFromArgs(2, argv)); ASSERT_EQUALS("cppcheck: error: Directory '' specified by --cppcheck-build-dir argument has to be existent.\n", GET_REDIRECT_OUTPUT); } }; From d4d77edeae25c2051ccf311ec9dd83fb0fd594b7 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Sat, 12 Aug 2023 23:46:31 +0200 Subject: [PATCH 03/30] Fix FP uninitStructMember / cleanup from #5311 (#5315) --- lib/astutils.cpp | 29 ++++++++++++++++------------- lib/astutils.h | 2 +- lib/checkother.cpp | 2 +- lib/checkuninitvar.cpp | 14 +++++++++----- test/testuninitvar.cpp | 28 ++++++++++++++++++++++++++++ 5 files changed, 55 insertions(+), 20 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index b1dc9900af7..db5058b073c 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -3129,30 +3129,33 @@ static ExprUsage getFunctionUsage(const Token* tok, int indirect, const Settings return ExprUsage::Inconclusive; } -ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings) +ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings, bool cpp) { - if (indirect > 0 && tok->astParent()) { - if (Token::Match(tok->astParent(), "%assign%") && astIsRHS(tok)) + const Token* const parent = tok->astParent(); + if (indirect > 0 && parent) { + if (Token::Match(parent, "%assign%") && astIsRHS(tok)) return ExprUsage::NotUsed; - if (tok->astParent()->isConstOp()) + if (parent->isConstOp()) return ExprUsage::NotUsed; - if (tok->astParent()->isCast()) + if (parent->isCast()) return ExprUsage::NotUsed; - if (Token::simpleMatch(tok->astParent(), ":") && Token::simpleMatch(tok->astParent()->astParent(), "?")) - return getExprUsage(tok->astParent()->astParent(), indirect, settings); + if (Token::simpleMatch(parent, ":") && Token::simpleMatch(parent->astParent(), "?")) + return getExprUsage(parent->astParent(), indirect, settings, cpp); } if (indirect == 0) { - if (Token::Match(tok->astParent(), "%cop%|%assign%|++|--") && !Token::Match(tok->astParent(), "=|>>") && - !tok->astParent()->isUnaryOp("&")) + if (Token::Match(parent, "%cop%|%assign%|++|--") && parent->str() != "=" && + !parent->isUnaryOp("&") && + !(astIsRHS(tok) && isLikelyStreamRead(cpp, parent))) return ExprUsage::Used; - if (Token::simpleMatch(tok->astParent(), "=") && astIsRHS(tok)) { - if (tok->astParent()->astOperand1() && tok->astParent()->astOperand1()->variable() && tok->astParent()->astOperand1()->variable()->isReference()) + if (Token::simpleMatch(parent, "=") && astIsRHS(tok)) { + const Token* const lhs = parent->astOperand1(); + if (lhs && lhs->variable() && lhs->variable()->isReference() && lhs == lhs->variable()->nameToken()) return ExprUsage::NotUsed; return ExprUsage::Used; } // Function call or index - if (((Token::simpleMatch(tok->astParent(), "(") && !tok->astParent()->isCast()) || (Token::simpleMatch(tok->astParent(), "[") && tok->valueType())) && - (astIsLHS(tok) || Token::simpleMatch(tok->astParent(), "( )"))) + if (((Token::simpleMatch(parent, "(") && !parent->isCast()) || (Token::simpleMatch(parent, "[") && tok->valueType())) && + (astIsLHS(tok) || Token::simpleMatch(parent, "( )"))) return ExprUsage::Used; } return getFunctionUsage(tok, indirect, settings); diff --git a/lib/astutils.h b/lib/astutils.h index 04143bc7f57..f486418ef71 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -409,7 +409,7 @@ bool isConstVarExpression(const Token* tok, std::function sk enum class ExprUsage { None, NotUsed, PassedByReference, Used, Inconclusive }; -ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings); +ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings, bool cpp); const Variable *getLHSVariable(const Token *tok); diff --git a/lib/checkother.cpp b/lib/checkother.cpp index f11a523a940..8663ed91e80 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -3388,7 +3388,7 @@ void CheckOther::checkAccessOfMovedVariable() else inconclusive = true; } else { - const ExprUsage usage = getExprUsage(tok, 0, mSettings); + const ExprUsage usage = getExprUsage(tok, 0, mSettings, mTokenizer->isCPP()); if (usage == ExprUsage::Used) accessOfMoved = true; if (usage == ExprUsage::PassedByReference) diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index 887e38b61b8..ca701d69723 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -709,8 +709,10 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var if (!membervar.empty()) { if (!suppressErrors && Token::Match(tok, "%name% . %name%") && tok->strAt(2) == membervar && Token::Match(tok->next()->astParent(), "%cop%|return|throw|?")) uninitStructMemberError(tok, tok->str() + "." + membervar); - else if (mTokenizer->isCPP() && !suppressErrors && Token::Match(tok, "%name%") && Token::Match(tok->astParent(), "return|throw|?")) - uninitStructMemberError(tok, tok->str() + "." + membervar); + else if (mTokenizer->isCPP() && !suppressErrors && Token::Match(tok, "%name%") && Token::Match(tok->astParent(), "return|throw|?")) { + if (std::any_of(tok->values().cbegin(), tok->values().cend(), std::mem_fn(&ValueFlow::Value::isUninitValue))) + uninitStructMemberError(tok, tok->str() + "." + membervar); + } } // Use variable @@ -1488,8 +1490,10 @@ bool CheckUninitVar::isMemberVariableUsage(const Token *tok, bool isPointer, All if (!isPointer && !Token::simpleMatch(tok->astParent(), ".") && Token::Match(tok->previous(), "[(,] %name% [,)]") && isVariableUsage(tok, isPointer, alloc)) return true; - if (!isPointer && Token::Match(tok->previous(), "= %name% ;")) - return true; + if (!isPointer && Token::Match(tok->previous(), "= %name% ;")) { + const Token* lhs = tok->previous()->astOperand1(); + return !(lhs && lhs->variable() && lhs->variable()->isReference() && lhs == lhs->variable()->nameToken()); + } // = *(&var); if (!isPointer && @@ -1639,7 +1643,7 @@ void CheckUninitVar::valueFlowUninit() if (!isleaf && Token::Match(tok->astParent(), ". %name%") && (tok->astParent()->next()->varId() || tok->astParent()->next()->isEnumerator())) continue; } - const ExprUsage usage = getExprUsage(tok, v->indirect, mSettings); + const ExprUsage usage = getExprUsage(tok, v->indirect, mSettings, mTokenizer->isCPP()); if (usage == ExprUsage::NotUsed || usage == ExprUsage::Inconclusive) continue; if (!v->subexpressions.empty() && usage == ExprUsage::PassedByReference) diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index f7432725df5..2a54b03c674 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -4787,6 +4787,21 @@ class TestUninitVar : public TestFixture { " }\n" "}"); ASSERT_EQUALS("", errout.str()); + + checkUninitVar("struct S { int x; };\n" + "S h() {\n" + " S s;\n" + " S& r = s;\n" + " r.x = 0;\n" + " return s;\n" + "}\n" + "S i() {\n" + " S s;\n" + " S& r{ s };\n" + " r.x = 0;\n" + " return s;\n" + "}"); + ASSERT_EQUALS("", errout.str()); } void uninitvar2_while() { @@ -6169,6 +6184,19 @@ class TestUninitVar : public TestFixture { " return s->i;\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + valueFlowUninit("int f(int i) {\n" + " int x;\n" + " int* p = &x;\n" + " return i >> *p;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: *p\n", errout.str()); + + valueFlowUninit("void f(int& x) {\n" + " int i;\n" + " x = i;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: i\n", errout.str()); } void valueFlowUninitBreak() { // Do not show duplicate warnings about the same uninitialized value From 53714556066c7d9d83eff0af046e26fcf6da56c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Sun, 13 Aug 2023 11:52:02 +0200 Subject: [PATCH 04/30] optimized pipe writing/reading and `ErrorMessage` serialization a bit (#5279) --- cli/processexecutor.cpp | 47 ++++++++++++++++++++++------------------- lib/errorlogger.cpp | 43 +++++++++++++++++++++++++------------ 2 files changed, 54 insertions(+), 36 deletions(-) diff --git a/cli/processexecutor.cpp b/cli/processexecutor.cpp index be9c61d1548..0bec1734e90 100644 --- a/cli/processexecutor.cpp +++ b/cli/processexecutor.cpp @@ -90,32 +90,35 @@ class PipeWriter : public ErrorLogger { private: // TODO: how to log file name in error? - void writeToPipe(PipeSignal type, const std::string &data) const + void writeToPipeInternal(PipeSignal type, const void* data, std::size_t to_write) const { - unsigned int len = static_cast(data.length() + 1); - char *out = new char[len + 1 + sizeof(len)]; - out[0] = static_cast(type); - std::memcpy(&(out[1]), &len, sizeof(len)); - std::memcpy(&(out[1+sizeof(len)]), data.c_str(), len); - - std::size_t bytes_to_write = len + 1 + sizeof(len); - ssize_t bytes_written = write(mWpipe, out, len + 1 + sizeof(len)); + const ssize_t bytes_written = write(mWpipe, data, to_write); if (bytes_written <= 0) { const int err = errno; - delete[] out; - out = nullptr; - std::cerr << "#### ThreadExecutor::writeToPipe() error for type " << type << ": " << std::strerror(err) << std::endl; + std::cerr << "#### ThreadExecutor::writeToPipeInternal() error for type " << type << ": " << std::strerror(err) << std::endl; std::exit(EXIT_FAILURE); } // TODO: write until everything is written - if (bytes_written != bytes_to_write) { - delete[] out; - out = nullptr; - std::cerr << "#### ThreadExecutor::writeToPipe() error for type " << type << ": insufficient data written (expected: " << bytes_to_write << " / got: " << bytes_written << ")" << std::endl; + if (bytes_written != to_write) { + std::cerr << "#### ThreadExecutor::writeToPipeInternal() error for type " << type << ": insufficient data written (expected: " << to_write << " / got: " << bytes_written << ")" << std::endl; std::exit(EXIT_FAILURE); } + } + + void writeToPipe(PipeSignal type, const std::string &data) const + { + { + const char t = static_cast(type); + writeToPipeInternal(type, &t, 1); + } + + const unsigned int len = static_cast(data.length() + 1); + { + static constexpr std::size_t l_size = sizeof(unsigned int); + writeToPipeInternal(type, &len, l_size); + } - delete[] out; + writeToPipeInternal(type, data.c_str(), len); } const int mWpipe; @@ -164,8 +167,8 @@ bool ProcessExecutor::handleRead(int rpipe, unsigned int &result, const std::str // Don't rely on incoming data being null-terminated. // Allocate +1 element and null-terminate the buffer. - char *buf = new char[len + 1]; - char *data_start = buf; + std::string buf(len + 1, '\0'); + char *data_start = &buf[0]; bytes_to_read = len; do { bytes_read = read(rpipe, data_start, bytes_to_read); @@ -177,13 +180,14 @@ bool ProcessExecutor::handleRead(int rpipe, unsigned int &result, const std::str bytes_to_read -= bytes_read; data_start += bytes_read; } while (bytes_to_read != 0); - buf[len] = 0; + buf[len] = '\0'; bool res = true; if (type == PipeWriter::REPORT_OUT) { // the first character is the color const Color c = static_cast(buf[0]); - mErrorLogger.reportOut(buf + 1, c); + // TODO: avoid string copy + mErrorLogger.reportOut(buf.substr(1), c); } else if (type == PipeWriter::REPORT_ERROR) { ErrorMessage msg; try { @@ -200,7 +204,6 @@ bool ProcessExecutor::handleRead(int rpipe, unsigned int &result, const std::str res = false; } - delete[] buf; return res; } diff --git a/lib/errorlogger.cpp b/lib/errorlogger.cpp index 08ac7fbae7f..b9cd3f5104f 100644 --- a/lib/errorlogger.cpp +++ b/lib/errorlogger.cpp @@ -227,35 +227,50 @@ Suppressions::ErrorMessage ErrorMessage::toSuppressionsErrorMessage() const return ret; } +static void serializeString(std::string &oss, const std::string & str) +{ + oss += std::to_string(str.length()); + oss += " "; + oss += str; +} std::string ErrorMessage::serialize() const { // Serialize this message into a simple string - std::ostringstream oss; - oss << id.length() << " " << id; - oss << Severity::toString(severity).length() << " " << Severity::toString(severity); - oss << MathLib::toString(cwe.id).length() << " " << MathLib::toString(cwe.id); - oss << MathLib::toString(hash).length() << " " << MathLib::toString(hash); - oss << file0.size() << " " << file0; + std::string oss; + serializeString(oss, id); + serializeString(oss, Severity::toString(severity)); + serializeString(oss, MathLib::toString(cwe.id)); + serializeString(oss, MathLib::toString(hash)); + serializeString(oss, file0); if (certainty == Certainty::inconclusive) { const std::string text("inconclusive"); - oss << text.length() << " " << text; + serializeString(oss, text); } const std::string saneShortMessage = fixInvalidChars(mShortMessage); const std::string saneVerboseMessage = fixInvalidChars(mVerboseMessage); - oss << saneShortMessage.length() << " " << saneShortMessage; - oss << saneVerboseMessage.length() << " " << saneVerboseMessage; - oss << callStack.size() << " "; + serializeString(oss, saneShortMessage); + serializeString(oss, saneVerboseMessage); + oss += std::to_string(callStack.size()); + oss += " "; for (std::list::const_iterator loc = callStack.cbegin(); loc != callStack.cend(); ++loc) { - std::ostringstream smallStream; - smallStream << (*loc).line << '\t' << (*loc).column << '\t' << (*loc).getfile(false) << '\t' << loc->getOrigFile(false) << '\t' << loc->getinfo(); - oss << smallStream.str().length() << " " << smallStream.str(); + std::string frame; + frame += std::to_string((*loc).line); + frame += '\t'; + frame += std::to_string((*loc).column); + frame += '\t'; + frame += (*loc).getfile(false); + frame += '\t'; + frame += loc->getOrigFile(false); + frame += '\t'; + frame += loc->getinfo(); + serializeString(oss, frame); } - return oss.str(); + return oss; } void ErrorMessage::deserialize(const std::string &data) From 466da1e77a5d351acfd3cc5ff2503a7ce4ff8dca Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Sun, 13 Aug 2023 22:24:17 +0200 Subject: [PATCH 05/30] Fix FP misusedScopedObject (#5321) --- lib/checkother.cpp | 2 +- test/testother.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 8663ed91e80..9ab231a36b1 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2139,7 +2139,7 @@ void CheckOther::checkMisusedScopedObject() return; auto getConstructorTok = [](const Token* tok, std::string& typeStr) -> const Token* { - if (!Token::Match(tok, "[;{}] %name%")) + if (!Token::Match(tok, "[;{}] %name%") || tok->next()->isKeyword()) return nullptr; tok = tok->next(); typeStr.clear(); diff --git a/test/testother.cpp b/test/testother.cpp index eb1b300122f..1d351ec342a 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -5648,6 +5648,12 @@ class TestOther : public TestFixture { "[test.cpp:6]: (style) Instance of 'std::scoped_lock' object is destroyed immediately.\n" "[test.cpp:9]: (style) Instance of 'std::scoped_lock' object is destroyed immediately.\n", errout.str()); + + check("struct S { int i; };\n" + "namespace {\n" + " S s() { return ::S{42}; }\n" + "}\n", "test.cpp"); + ASSERT_EQUALS("", errout.str()); } void testMisusedScopeObjectAssignment() { // #11371 From 48c91abba685d28129a8d89ce5c6d0e375c1e2b1 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Sun, 13 Aug 2023 15:31:38 -0500 Subject: [PATCH 06/30] Fix issue 11867: Assert failure in valueFlowContainerSize() (#5317) --- lib/astutils.cpp | 12 ++++++++++++ lib/astutils.h | 1 + lib/valueflow.cpp | 35 +++++++++++++++++++++++------------ test/testcondition.cpp | 15 +++++++++++++++ 4 files changed, 51 insertions(+), 12 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index db5058b073c..e69b78659f5 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -259,6 +259,18 @@ bool astIsContainerOwned(const Token* tok) { return astIsContainer(tok) && !astIsContainerView(tok); } +bool astIsContainerString(const Token* tok) +{ + if (!tok) + return false; + if (!tok->valueType()) + return false; + const Library::Container* container = tok->valueType()->container; + if (!container) + return false; + return container->stdStringLike; +} + static const Token* getContainerFunction(const Token* tok) { if (!tok || !tok->valueType() || !tok->valueType()->container) diff --git a/lib/astutils.h b/lib/astutils.h index f486418ef71..4ffd0aa792a 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -149,6 +149,7 @@ bool astIsContainer(const Token *tok); bool astIsContainerView(const Token* tok); bool astIsContainerOwned(const Token* tok); +bool astIsContainerString(const Token* tok); Library::Container::Action astContainerAction(const Token* tok, const Token** ftok = nullptr); Library::Container::Yield astContainerYield(const Token* tok, const Token** ftok = nullptr); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 85a64f022ac..c18e2ce4586 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -696,7 +696,11 @@ static void setTokenValue(Token* tok, if (value.isImpossible()) { if (value.intvalue == 0) v.setKnown(); - else + else if ((value.bound == ValueFlow::Value::Bound::Upper && value.intvalue > 0) || + (value.bound == ValueFlow::Value::Bound::Lower && value.intvalue < 0)) { + v.intvalue = 0; + v.setKnown(); + } else v.setPossible(); } else { v.intvalue = !v.intvalue; @@ -8660,6 +8664,9 @@ static void valueFlowContainerSetTokValue(TokenList& tokenlist, const Settings* ValueFlow::Value value; value.valueType = ValueFlow::Value::ValueType::TOK; value.tokvalue = initList; + if (astIsContainerString(tok) && Token::simpleMatch(initList, "{") && Token::Match(initList->astOperand2(), "%str%")) { + value.tokvalue = initList->astOperand2(); + } value.setKnown(); Token* start = initList->link() ? initList->link() : initList->next(); if (tok->variable() && tok->variable()->isConst()) { @@ -8675,6 +8682,19 @@ static const Scope* getFunctionScope(const Scope* scope) { return scope; } +static MathLib::bigint valueFlowGetStrLength(const Token* tok) +{ + if (tok->tokType() == Token::eString) + return Token::getStrLength(tok); + if (astIsGenericChar(tok) || tok->tokType() == Token::eChar) + return 1; + if (const ValueFlow::Value* v2 = tok->getKnownValue(ValueFlow::Value::ValueType::CONTAINER_SIZE)) + return v2->intvalue; + if (const ValueFlow::Value* v1 = tok->getKnownValue(ValueFlow::Value::ValueType::TOK)) + return valueFlowGetStrLength(v1->tokvalue); + return 0; +} + static void valueFlowContainerSize(TokenList& tokenlist, const SymbolDatabase& symboldatabase, ErrorLogger* /*errorLogger*/, @@ -8819,21 +8839,12 @@ static void valueFlowContainerSize(TokenList& tokenlist, } else if (Token::simpleMatch(tok, "+=") && astIsContainer(tok->astOperand1())) { const Token* containerTok = tok->astOperand1(); const Token* valueTok = tok->astOperand2(); - MathLib::bigint size = 0; - if (valueTok->tokType() == Token::eString) - size = Token::getStrLength(valueTok); - else if (astIsGenericChar(tok) || valueTok->tokType() == Token::eChar) - size = 1; - else if (const ValueFlow::Value* v1 = valueTok->getKnownValue(ValueFlow::Value::ValueType::TOK)) - size = Token::getStrLength(v1->tokvalue); - else if (const ValueFlow::Value* v2 = - valueTok->getKnownValue(ValueFlow::Value::ValueType::CONTAINER_SIZE)) - size = v2->intvalue; + MathLib::bigint size = valueFlowGetStrLength(valueTok); if (size == 0) continue; ValueFlow::Value value(size - 1); value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE; - value.bound = ValueFlow::Value::Bound::Lower; + value.bound = ValueFlow::Value::Bound::Upper; value.setImpossible(); Token* next = nextAfterAstRightmostLeaf(tok); if (!next) diff --git a/test/testcondition.cpp b/test/testcondition.cpp index c79b50a842e..5cca85c05a8 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -5028,6 +5028,21 @@ class TestCondition : public TestFixture { " return -1;\n" "}\n"); ASSERT_EQUALS("[test.cpp:5]: (style) Condition 's.empty()' is always false\n", errout.str()); + + check("void f(std::string& p) {\n" + " const std::string d{ \"abc\" };\n" + " p += d;\n" + " if(p.empty()) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (style) Condition 'p.empty()' is always false\n", errout.str()); + + check("bool f(int i, FILE* fp) {\n" + " std::string s = \"abc\";\n" + " s += std::to_string(i);\n" + " s += \"\\n\";\n" + " return fwrite(s.c_str(), 1, s.length(), fp) == s.length();\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void alwaysTrueLoop() From 52081ef08fcb90b61ae02cc9b8167e78fd7737ee Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Mon, 14 Aug 2023 03:27:00 -0500 Subject: [PATCH 07/30] Add special function to match lifetimes (#5320) This also removes the termination checking in `valueFlowUninit` as this causes a lot of FNs. --- lib/checkuninitvar.cpp | 4 +++- lib/valueflow.cpp | 43 ++++++++++++++++++++++++++++-------------- test/testuninitvar.cpp | 9 ++++----- 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index ca701d69723..239f1ad8d9a 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -710,7 +710,9 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var if (!suppressErrors && Token::Match(tok, "%name% . %name%") && tok->strAt(2) == membervar && Token::Match(tok->next()->astParent(), "%cop%|return|throw|?")) uninitStructMemberError(tok, tok->str() + "." + membervar); else if (mTokenizer->isCPP() && !suppressErrors && Token::Match(tok, "%name%") && Token::Match(tok->astParent(), "return|throw|?")) { - if (std::any_of(tok->values().cbegin(), tok->values().cend(), std::mem_fn(&ValueFlow::Value::isUninitValue))) + if (std::any_of(tok->values().cbegin(), tok->values().cend(), [](const ValueFlow::Value& v) { + return v.isUninitValue() && !v.isInconclusive(); + })) uninitStructMemberError(tok, tok->str() + "." + membervar); } } diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index c18e2ce4586..713b2dad915 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -641,9 +641,10 @@ static void setTokenValue(Token* tok, } } - if (Token::simpleMatch(parent, "=") && astIsRHS(tok) && !value.isLifetimeValue()) { - setTokenValue(parent, std::move(value), settings); - return; + if (Token::simpleMatch(parent, "=") && astIsRHS(tok)) { + setTokenValue(parent, value, settings); + if (!value.isUninitValue()) + return; } if (value.isContainerSizeValue() && astIsContainer(tok)) { @@ -2433,6 +2434,20 @@ struct ValueFlowAnalyzer : Analyzer { return settings; } + // Returns Action::Match if its an exact match, return Action::Read if it partially matches the lifetime + Action analyzeLifetime(const Token* tok) const + { + if (!tok) + return Action::None; + if (match(tok)) + return Action::Match; + if (Token::simpleMatch(tok, ".") && analyzeLifetime(tok->astOperand1()) != Action::None) + return Action::Read; + if (astIsRHS(tok) && Token::simpleMatch(tok->astParent(), ".")) + return analyzeLifetime(tok->astParent()); + return Action::None; + } + struct ConditionState { bool dependent = true; bool unknown = true; @@ -2806,7 +2821,10 @@ struct ValueFlowAnalyzer : Analyzer { return Action::None; lifeTok = v.tokvalue; } - if (lifeTok && match(lifeTok)) { + if (!lifeTok) + return Action::None; + Action la = analyzeLifetime(lifeTok); + if (la.matches()) { Action a = Action::Read; if (isModified(tok).isModified()) a = Action::Invalid; @@ -2816,6 +2834,9 @@ struct ValueFlowAnalyzer : Analyzer { return Action::Inconclusive; return a; } + if (la.isRead()) { + return isAliasModified(tok); + } return Action::None; } else if (isAlias(ref, inconclusive)) { @@ -3299,12 +3320,6 @@ struct MemberExpressionAnalyzer : SubExpressionAnalyzer { : SubExpressionAnalyzer(e, std::move(val), t, s), varname(std::move(varname)) {} - bool match(const Token* tok) const override - { - return SubExpressionAnalyzer::match(tok) || - (Token::simpleMatch(tok->astParent(), ".") && SubExpressionAnalyzer::match(tok->astParent())); - } - bool submatch(const Token* tok, bool exact) const override { if (!Token::Match(tok, ". %var%")) @@ -3334,6 +3349,8 @@ static std::string lifetimeType(const Token *tok, const ValueFlow::Value *val) case ValueFlow::Value::LifetimeKind::Address: if (astIsPointer(tok)) result = "pointer"; + else if (Token::simpleMatch(tok, "=") && astIsPointer(tok->astOperand2())) + result = "pointer"; else result = "object"; break; @@ -7977,7 +7994,6 @@ static void valueFlowUninit(TokenList& tokenlist, const Settings* settings) Token* start = findStartToken(var, tok->next(), &settings->library); std::map partialReads; - Analyzer::Result result; if (const Scope* scope = var->typeScope()) { if (Token::findsimplematch(scope->bodyStart, "union", scope->bodyEnd)) continue; @@ -7992,7 +8008,7 @@ static void valueFlowUninit(TokenList& tokenlist, const Settings* settings) continue; } MemberExpressionAnalyzer analyzer(memVar.nameToken()->str(), tok, uninitValue, tokenlist, settings); - result = valueFlowGenericForward(start, tok->scope()->bodyEnd, analyzer, *settings); + valueFlowGenericForward(start, tok->scope()->bodyEnd, analyzer, *settings); for (auto&& p : *analyzer.partialReads) { Token* tok2 = p.first; @@ -8022,8 +8038,7 @@ static void valueFlowUninit(TokenList& tokenlist, const Settings* settings) if (partial) continue; - if (result.terminate != Analyzer::Terminate::Modified) - valueFlowForward(start, tok->scope()->bodyEnd, var->nameToken(), uninitValue, tokenlist, settings); + valueFlowForward(start, tok->scope()->bodyEnd, var->nameToken(), uninitValue, tokenlist, settings); } } diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index 2a54b03c674..9cc8b5030cb 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -6209,7 +6209,7 @@ class TestUninitVar : public TestFixture { " memcpy(wcsin, x, sizeof(wcsstruct));\n" // <- warning " x->wcsprm = NULL;\n" // <- no warning "}"); - ASSERT_EQUALS("[test.cpp:7]: (error) Uninitialized variable: x.wcsprm\n", errout.str()); + ASSERT_EQUALS("[test.cpp:7]: (error) Uninitialized variable: x\n", errout.str()); valueFlowUninit("struct wcsstruct {\n" " int *wcsprm;\n" @@ -7037,8 +7037,7 @@ class TestUninitVar : public TestFixture { " memcpy(in, s, sizeof(S));\n" " s->p = NULL;\n" "}\n"); - ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: s.p\n", - errout.str()); + ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: s\n", errout.str()); valueFlowUninit("struct S {\n" // #11321 " int a = 0;\n" @@ -7298,7 +7297,7 @@ class TestUninitVar : public TestFixture { " A::B b;\n" " x.push_back(b);\n" "}\n"); - ASSERT_EQUALS("[test.cpp:9]: (error) Uninitialized variable: b.i\n", errout.str()); + ASSERT_EQUALS("[test.cpp:9]: (error) Uninitialized variable: b\n", errout.str()); valueFlowUninit("struct A {\n" " struct B {\n" @@ -7322,7 +7321,7 @@ class TestUninitVar : public TestFixture { " A a;\n" " x.push_back(a);\n" "}\n"); - ASSERT_EQUALS("[test.cpp:9]: (error) Uninitialized variable: a.j\n", errout.str()); + ASSERT_EQUALS("[test.cpp:9]: (error) Uninitialized variable: a\n", errout.str()); valueFlowUninit("struct S { struct T { int* p; } t[2]; };\n" // #11018 "void f() {\n" From d076da8f7cddeb20ef176531af20e18fa273673f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Mon, 14 Aug 2023 10:29:04 +0200 Subject: [PATCH 08/30] added missing `__GNUC__` define for selfcheck (#5324) This was causing some code not to be enabled in the selfchecks leading to some missing warnings. --- .github/workflows/CI-unixish.yml | 4 +++- .github/workflows/asan.yml | 2 +- .github/workflows/tsan.yml | 2 +- .github/workflows/ubsan.yml | 2 +- cli/cppcheckexecutorsig.cpp | 7 ++++++- createrelease | 4 ++-- 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/.github/workflows/CI-unixish.yml b/.github/workflows/CI-unixish.yml index 902417375a8..1e51f0d6faa 100644 --- a/.github/workflows/CI-unixish.yml +++ b/.github/workflows/CI-unixish.yml @@ -460,9 +460,11 @@ jobs: - name: Self check run: | - selfcheck_options="-q -j$(nproc) --std=c++11 --template=selfcheck --showtime=top5 -D__CPPCHECK__ -DCHECK_INTERNAL -DHAVE_RULES --error-exitcode=1 --inline-suppr --suppressions-list=.selfcheck_suppressions --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2/ --inconclusive --enable=style,performance,portability,warning,missingInclude,internal --exception-handling --debug-warnings --check-level=exhaustive" + selfcheck_options="-q -j$(nproc) --std=c++11 --template=selfcheck --showtime=top5 -D__CPPCHECK__ -D__GNUC__ -DCHECK_INTERNAL -DHAVE_RULES --error-exitcode=1 --inline-suppr --suppressions-list=.selfcheck_suppressions --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2/ --inconclusive --enable=style,performance,portability,warning,missingInclude,internal --exception-handling --debug-warnings --check-level=exhaustive" ec=0 + # TODO: add --check-config + # early exit if [ $ec -eq 1 ]; then exit $ec diff --git a/.github/workflows/asan.yml b/.github/workflows/asan.yml index fe7c5a95a77..c29ecde8a4a 100644 --- a/.github/workflows/asan.yml +++ b/.github/workflows/asan.yml @@ -82,7 +82,7 @@ jobs: - name: Self check if: false run: | - selfcheck_options="-q -j$(nproc) --std=c++11 --template=selfcheck --showtime=top5 -D__CPPCHECK__ -DCHECK_INTERNAL -DHAVE_RULES --error-exitcode=1 --inline-suppr --suppressions-list=.selfcheck_suppressions --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2/ --inconclusive --enable=style,performance,portability,warning,missingInclude,internal --exception-handling --debug-warnings" + selfcheck_options="-q -j$(nproc) --std=c++11 --template=selfcheck --showtime=top5 -D__CPPCHECK__ -D__GNUC__ -DCHECK_INTERNAL -DHAVE_RULES --error-exitcode=1 --inline-suppr --suppressions-list=.selfcheck_suppressions --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2/ --inconclusive --enable=style,performance,portability,warning,missingInclude,internal --exception-handling --debug-warnings" ec=0 ./cmake.output/bin/cppcheck $selfcheck_options --addon=naming.json cli lib || ec=1 ./cmake.output/bin/cppcheck $selfcheck_options -DQT_VERSION=0x050000 -DQ_MOC_OUTPUT_REVISION=67 -DQT_CHARTS_LIB --library=qt --addon=naming.json -Icmake.output/gui -Igui gui/*.cpp cmake.output/gui/*.cpp || ec=1 diff --git a/.github/workflows/tsan.yml b/.github/workflows/tsan.yml index 6114817c194..876e1976141 100644 --- a/.github/workflows/tsan.yml +++ b/.github/workflows/tsan.yml @@ -82,7 +82,7 @@ jobs: - name: Self check if: false run: | - selfcheck_options="-q -j$(nproc) --std=c++11 --template=selfcheck --showtime=top5 -D__CPPCHECK__ -DCHECK_INTERNAL -DHAVE_RULES --error-exitcode=0 --inline-suppr --suppressions-list=.selfcheck_suppressions --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2/ --inconclusive --enable=style,performance,portability,warning,missingInclude,internal --exception-handling --debug-warnings" + selfcheck_options="-q -j$(nproc) --std=c++11 --template=selfcheck --showtime=top5 -D__CPPCHECK__ -D__GNUC__ -DCHECK_INTERNAL -DHAVE_RULES --error-exitcode=0 --inline-suppr --suppressions-list=.selfcheck_suppressions --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2/ --inconclusive --enable=style,performance,portability,warning,missingInclude,internal --exception-handling --debug-warnings" ec=0 ./cmake.output/bin/cppcheck $selfcheck_options --addon=naming.json -DCHECK_INTERNAL cli lib || ec=1 ./cmake.output/bin/cppcheck $selfcheck_options -DQT_VERSION=0x050000 -DQ_MOC_OUTPUT_REVISION=67 -DQT_CHARTS_LIB --library=qt --addon=naming.json -Icmake.output/gui -Igui gui/*.cpp cmake.output/gui/*.cpp || ec=1 diff --git a/.github/workflows/ubsan.yml b/.github/workflows/ubsan.yml index 3076801002e..2a422710b74 100644 --- a/.github/workflows/ubsan.yml +++ b/.github/workflows/ubsan.yml @@ -78,7 +78,7 @@ jobs: # TODO: only fail the step on sanitizer issues - since we use processes it will only fail the underlying process which will result in an cppcheckError - name: Self check run: | - selfcheck_options="-q -j$(nproc) --std=c++11 --template=selfcheck --showtime=top5 -D__CPPCHECK__ -DCHECK_INTERNAL -DHAVE_RULES --error-exitcode=1 --inline-suppr --suppressions-list=.selfcheck_suppressions --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2/ --inconclusive --enable=style,performance,portability,warning,missingInclude,internal --exception-handling --debug-warnings" + selfcheck_options="-q -j$(nproc) --std=c++11 --template=selfcheck --showtime=top5 -D__CPPCHECK__ -D__GNUC__ -DCHECK_INTERNAL -DHAVE_RULES --error-exitcode=1 --inline-suppr --suppressions-list=.selfcheck_suppressions --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2/ --inconclusive --enable=style,performance,portability,warning,missingInclude,internal --exception-handling --debug-warnings" ec=0 ./cmake.output/bin/cppcheck $selfcheck_options --addon=naming.json cli lib || ec=1 ./cmake.output/bin/cppcheck $selfcheck_options -DQT_VERSION=0x050000 -DQ_MOC_OUTPUT_REVISION=67 -DQT_CHARTS_LIB --library=qt --addon=naming.json -Icmake.output/gui -Igui gui/*.cpp cmake.output/gui/*.cpp || ec=1 diff --git a/cli/cppcheckexecutorsig.cpp b/cli/cppcheckexecutorsig.cpp index e8d447682eb..c5347d8e5ac 100644 --- a/cli/cppcheckexecutorsig.cpp +++ b/cli/cppcheckexecutorsig.cpp @@ -101,6 +101,7 @@ static const Signalmap_t listofsignals = { * but when ending up here something went terribly wrong anyway. * And all which is left is just printing some information and terminate. */ +// cppcheck-suppress constParameterCallback static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context) { int type = -1; @@ -119,7 +120,9 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context) const Signalmap_t::const_iterator it=listofsignals.find(signo); const char * const signame = (it==listofsignals.end()) ? "unknown" : it->second.c_str(); +#ifdef USE_UNIX_BACKTRACE_SUPPORT bool lowMem=false; // was low-memory condition detected? Be careful then! Avoid allocating much more memory then. +#endif bool unexpectedSignal=true; // unexpected indicates program failure bool terminate=true; // exit process/thread const bool isAddressOnStack = IsAddressOnStack(info->si_addr); @@ -135,7 +138,9 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context) " - out of memory or assertion?\n", #endif output); +#ifdef USE_UNIX_BACKTRACE_SUPPORT lowMem=true; // educated guess +#endif break; case SIGBUS: fputs("Internal error: cppcheck received signal ", output); @@ -296,7 +301,7 @@ int check_wrapper_sig(CppCheckExecutor& executor, int (CppCheckExecutor::*f)(Cpp { // determine stack vs. heap char stackVariable; - char *heapVariable=(char*)malloc(1); + char *heapVariable=static_cast(malloc(1)); bStackBelowHeap = &stackVariable < heapVariable; free(heapVariable); diff --git a/createrelease b/createrelease index c99964be13d..0a98f850266 100755 --- a/createrelease +++ b/createrelease @@ -11,7 +11,7 @@ # # self check, fix critical issues: # make clean && make CXXFLAGS=-O2 MATCHCOMPILER=yes -j4 -# ./cppcheck -D__CPPCHECK__ -DCHECK_INTERNAL -DHAVE_RULES --std=c++11 --library=cppcheck-lib --library=qt --enable=style --inconclusive --inline-suppr --suppress=bitwiseOnBoolean --suppress=shadowFunction --suppress=useStlAlgorithm --suppress=*:externals/picojson.h --suppress=functionConst --suppress=functionStatic --xml cli gui/*.cpp lib 2> selfcheck.xml +# ./cppcheck -D__CPPCHECK__ -D__GNUC__ -DCHECK_INTERNAL -DHAVE_RULES --std=c++11 --library=cppcheck-lib --library=qt --enable=style --inconclusive --inline-suppr --suppress=bitwiseOnBoolean --suppress=shadowFunction --suppress=useStlAlgorithm --suppress=*:externals/picojson.h --suppress=functionConst --suppress=functionStatic --xml cli gui/*.cpp lib 2> selfcheck.xml # # Update translations # lupdate gui.pro @@ -82,7 +82,7 @@ # 2. scp -i ../.ssh/osuosl_id_rsa tools/donate-cpu-server.py danielmarjamaki@cppcheck1.osuosl.org:/var/daca@home/ # # self check, fix stylistic issues: -# ./cppcheck -D__CPPCHECK__ -DCHECK_INTERNAL -DHAVE_RULES --library=cppcheck-lib --enable=style --inconclusive --inline-suppr --suppress=bitwiseOnBoolean --suppress=shadowFunction --suppress=useStlAlgorithm --suppress=*:externals/picojson.h cli gui/*.cpp lib +# ./cppcheck -D__CPPCHECK__ -D__GNUC__ -DCHECK_INTERNAL -DHAVE_RULES --library=cppcheck-lib --enable=style --inconclusive --inline-suppr --suppress=bitwiseOnBoolean --suppress=shadowFunction --suppress=useStlAlgorithm --suppress=*:externals/picojson.h cli gui/*.cpp lib # # Set debug version (see 803eea912c9512c810a7e78d58bb927d89a6daa1) From 693084470dab8e2eab87a55bc966cd3afcdb0599 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Mon, 14 Aug 2023 11:37:59 +0200 Subject: [PATCH 09/30] TestCmdlineParser: fixed some TODO test cases (#5325) --- Makefile | 2 +- test/testcmdlineparser.cpp | 71 +++++++++++++++++++++++++++----------- 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 946755da0cb..6a2b1faad77 100644 --- a/Makefile +++ b/Makefile @@ -716,7 +716,7 @@ test/testclangimport.o: test/testclangimport.cpp lib/check.h lib/clangimport.h l test/testclass.o: test/testclass.cpp externals/simplecpp/simplecpp.h lib/check.h lib/checkclass.h 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/preprocessor.h lib/settings.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testclass.cpp -test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/cmdlineparser.h cli/cppcheckexecutor.h lib/check.h 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/fixture.h test/redirect.h +test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/cmdlineparser.h cli/cppcheckexecutor.h lib/check.h 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/vfvalue.h test/fixture.h test/helpers.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcmdlineparser.cpp test/testcolor.o: test/testcolor.cpp lib/check.h 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/utils.h test/fixture.h diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index ca91e7c3c02..5fdd05adcf5 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -20,6 +20,7 @@ #include "config.h" #include "cppcheckexecutor.h" #include "errortypes.h" +#include "helpers.h" #include "platform.h" #include "redirect.h" #include "settings.h" @@ -608,12 +609,18 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } - // TODO: fails since the file is not found void includesFile() { REDIRECT; - const char * const argv[] = {"cppcheck", "--includes-file=fileThatDoesNotExist.txt", "file.cpp"}; - TODO_ASSERT_EQUALS(true, false, parser->parseFromArgs(3, argv)); - TODO_ASSERT_EQUALS("", "cppcheck: error: unable to open includes file at 'fileThatDoesNotExist.txt'\n", GET_REDIRECT_OUTPUT); + ScopedFile file("includes.txt", + "path/sub\n" + "path2/sub1\n"); + const char * const argv[] = {"cppcheck", "--includes-file=includes.txt", "file.cpp"}; + ASSERT_EQUALS(true, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(2, settings->includePaths.size()); + auto it = settings->includePaths.cbegin(); + ASSERT_EQUALS("path/sub/", *it++); + ASSERT_EQUALS("path2/sub1/", *it); + ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void includesFileNoFile() { @@ -623,14 +630,19 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS("cppcheck: error: unable to open includes file at 'fileThatDoesNotExist.txt'\n", GET_REDIRECT_OUTPUT); } - // TODO: fails since the file is not found void configExcludesFile() { REDIRECT; - const char * const argv[] = {"cppcheck", "--config-excludes-file=fileThatDoesNotExist.txt", "file.cpp"}; - settings->includePaths.clear(); - TODO_ASSERT_EQUALS(true, false, parser->parseFromArgs(3, argv)); - // TODO: add checks - TODO_ASSERT_EQUALS("", "cppcheck: error: unable to open config excludes file at 'fileThatDoesNotExist.txt'\n", GET_REDIRECT_OUTPUT); + ScopedFile file("excludes.txt", + "path/sub\n" + "path2/sub1\n"); + const char * const argv[] = {"cppcheck", "--config-excludes-file=excludes.txt", "file.cpp"}; + settings->configExcludePaths.clear(); + ASSERT_EQUALS(true, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(2, settings->configExcludePaths.size()); + auto it = settings->configExcludePaths.cbegin(); + ASSERT_EQUALS("path/sub/", *it++); + ASSERT_EQUALS("path2/sub1/", *it); + ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void configExcludesFileNoFile() { @@ -897,11 +909,17 @@ class TestCmdlineParser : public TestFixture { } void exitcodeSuppressions() { - // TODO: Fails since cannot open the file REDIRECT; + ScopedFile file("suppr.txt", + "uninitvar\n" + "unusedFunction\n"); const char * const argv[] = {"cppcheck", "--exitcode-suppressions=suppr.txt", "file.cpp"}; - TODO_ASSERT_EQUALS(true, false, parser->parseFromArgs(3, argv)); - TODO_ASSERT_EQUALS("", "cppcheck: error: couldn't open the file: \"suppr.txt\".\n", GET_REDIRECT_OUTPUT); + ASSERT_EQUALS(true, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(2, settings->nofail.getSuppressions().size()); + auto it = settings->nofail.getSuppressions().cbegin(); + ASSERT_EQUALS("uninitvar", (*it++).errorId); + ASSERT_EQUALS("unusedFunction", (*it).errorId); + ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void exitcodeSuppressionsNoFile() { @@ -911,14 +929,19 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS("cppcheck: error: unrecognized command line option: \"--exitcode-suppressions\".\n", GET_REDIRECT_OUTPUT); } - // TODO: file does not exist void fileList() { REDIRECT; + ScopedFile file("files.txt", + "file1.c\n" + "file2.cpp\n"); const char * const argv[] = {"cppcheck", "--file-list=files.txt", "file.cpp"}; - TODO_ASSERT_EQUALS(true, false, parser->parseFromArgs(3, argv)); - // TODO: settings are not being reset after each test - //TODO_ASSERT_EQUALS(4, 1, defparser->getPathNames().size()); - TODO_ASSERT_EQUALS("", "cppcheck: error: couldn't open the file: \"files.txt\".\n", GET_REDIRECT_OUTPUT); + ASSERT_EQUALS(true, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(3, parser->getPathNames().size()); + auto it = parser->getPathNames().cbegin(); + ASSERT_EQUALS("file1.c", *it++); + ASSERT_EQUALS("file2.cpp", *it++); + ASSERT_EQUALS("file.cpp", *it); + ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void fileListNoFile() { @@ -1226,11 +1249,17 @@ class TestCmdlineParser : public TestFixture { } void suppressions() { - // TODO: Fails because there is no suppr.txt file! REDIRECT; + ScopedFile file("suppr.txt", + "uninitvar\n" + "unusedFunction\n"); const char * const argv[] = {"cppcheck", "--suppressions-list=suppr.txt", "file.cpp"}; - TODO_ASSERT_EQUALS(true, false, parser->parseFromArgs(3, argv)); - TODO_ASSERT_EQUALS("", "cppcheck: error: couldn't open the file: \"suppr.txt\".\n", GET_REDIRECT_OUTPUT); + ASSERT_EQUALS(true, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(2, settings->nomsg.getSuppressions().size()); + auto it = settings->nomsg.getSuppressions().cbegin(); + ASSERT_EQUALS("uninitvar", (*it++).errorId); + ASSERT_EQUALS("unusedFunction", (*it).errorId); + ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } void suppressionsNoFile1() { From d064f9c24352552e94d7f1f13bdf3b797b2570cb Mon Sep 17 00:00:00 2001 From: "Ryan M. Lederman" Date: Mon, 14 Aug 2023 03:55:32 -0600 Subject: [PATCH 10/30] -j 0 causes indefinite hang. require >= 1 (#5326) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In cppcheck 2.11.1 (macOS), using `-j 0` actually causes cppcheck to do nothing–it stalls indefinitely. I could only find one place where `mSettings.jobs` was validated against > 0 and it's simply an assert, so you wouldn't hit it in a release build. - Require -j >= 1 ✅ - Cap -j at 1024, not 10000 ✅ (I don't even know what would happen if you created 10,000 threads, but nothing good; likely exhaust virtual memory or grind the process to a halt). 1024 is still obscene but there may be some hypercomputers out there that have that many logical cores. --- cli/cmdlineparser.cpp | 15 +++++++++++---- test/testcmdlineparser.cpp | 12 ++++++++++-- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 92b5c6a0a78..f7826fef540 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -507,10 +507,17 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) printError("argument to '-j' is not valid - " + err + "."); return false; } - if (tmp > 10000) { - // This limit is here just to catch typos. If someone has - // need for more jobs, this value should be increased. - printError("argument for '-j' is allowed to be 10000 at max."); + if (tmp == 0) { + // TODO: implement get CPU logical core count and use that. + // Usually, -j 0 would mean "use all available cores," but + // if we get a 0, we just stall and don't do any work. + printError("argument for '-j' must be greater than 0."); + return false; + } + if (tmp > 1024) { + // Almost nobody has 1024 logical cores, but somebody out + // there does. + printError("argument for '-j' is allowed to be 1024 at max."); return false; } mSettings.jobs = tmp; diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index 5fdd05adcf5..d60006ccd5f 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -142,6 +142,7 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(jobs2); TEST_CASE(jobsMissingCount); TEST_CASE(jobsInvalid); + TEST_CASE(jobsNoJobs); TEST_CASE(jobsTooBig); TEST_CASE(maxConfigs); TEST_CASE(maxConfigsMissingCount); @@ -1010,11 +1011,18 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS("cppcheck: error: argument to '-j' is not valid - not an integer.\n", GET_REDIRECT_OUTPUT); } + void jobsNoJobs() { + REDIRECT; + const char * const argv[] = {"cppcheck", "-j0", "file.cpp"}; + ASSERT(!parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("cppcheck: error: argument for '-j' must be greater than 0.\n", GET_REDIRECT_OUTPUT); + } + void jobsTooBig() { REDIRECT; - const char * const argv[] = {"cppcheck", "-j10001", "file.cpp"}; + const char * const argv[] = {"cppcheck", "-j1025", "file.cpp"}; ASSERT(!parser->parseFromArgs(3, argv)); - ASSERT_EQUALS("cppcheck: error: argument for '-j' is allowed to be 10000 at max.\n", GET_REDIRECT_OUTPUT); + ASSERT_EQUALS("cppcheck: error: argument for '-j' is allowed to be 1024 at max.\n", GET_REDIRECT_OUTPUT); } void maxConfigs() { From c257c70347020b9f4ee00d5d02dd3823015ef3bb Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 14 Aug 2023 14:32:35 +0200 Subject: [PATCH 11/30] Fix #11546 FP danglingTemporaryLifetime with unknown member (#5256) --- lib/valueflow.cpp | 27 ++++++++++++++++----------- test/testautovariables.cpp | 13 +++++++++++++ 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 713b2dad915..c6ba15f6855 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -4256,28 +4256,33 @@ struct LifetimeStore { } }; -static bool isOwningVariables(const std::list& vars, int depth = 10) +static bool hasBorrowingVariables(const std::list& vars, const std::vector& args, int depth = 10) { if (depth < 0) return false; - return vars.empty() || std::all_of(vars.cbegin(), vars.cend(), [&](const Variable& var) { - if (var.isReference() || var.isPointer()) - return false; + return std::any_of(vars.cbegin(), vars.cend(), [&](const Variable& var) { const ValueType* vt = var.valueType(); if (vt) { - if (vt->pointer > 0) + if (vt->pointer > 0 && + std::none_of(args.begin(), args.end(), [vt](const Token* arg) { + return arg->valueType() && arg->valueType()->type == vt->type; + })) return false; - if (vt->isPrimitive()) + if (vt->pointer > 0) return true; - if (vt->isEnum()) + if (vt->reference != Reference::None) return true; + if (vt->isPrimitive()) + return false; + if (vt->isEnum()) + return false; // TODO: Check container inner type if (vt->type == ValueType::CONTAINER && vt->container) - return !vt->container->view; + return vt->container->view; if (vt->typeScope) - return isOwningVariables(vt->typeScope->varlist, depth - 1); + return hasBorrowingVariables(vt->typeScope->varlist, args, depth - 1); } - return false; + return true; }); } @@ -4354,7 +4359,7 @@ static void valueFlowLifetimeUserConstructor(Token* tok, else ls.byVal(tok, tokenlist, errorLogger, settings); }); - } else if (!isOwningVariables(constructor->nestedIn->varlist)) { + } else if (hasBorrowingVariables(constructor->nestedIn->varlist, args)) { LifetimeStore::forEach(args, "Passed to constructor of '" + name + "'.", ValueFlow::Value::LifetimeKind::SubObject, diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index 0ee1d84132a..159782782d3 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -3647,6 +3647,19 @@ class TestAutoVariables : public TestFixture { "}\n", true); ASSERT_EQUALS("", errout.str()); + + check("struct S {\n" + " explicit S(const char* p) { m = p; }\n" + " void g();\n" + " std::string m;\n" + " int* t{};\n" + "};\n" + "void f(const std::stringstream& buffer) {\n" + " S s(buffer.str().c_str());\n" + " s.g();\n" + "}\n", + true); + ASSERT_EQUALS("", errout.str()); } void danglingLifetimeAggegrateConstructor() { From 8aa9d710d11ec98a5b9cdf3353c5773aff04bbb0 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Mon, 14 Aug 2023 08:17:05 -0500 Subject: [PATCH 12/30] Fix 11844: FP negativeIndex for known loop (#5282) --- lib/astutils.cpp | 9 ++++++++- lib/token.cpp | 27 +++++++++++++++++++++------ lib/token.h | 1 + test/testbufferoverrun.cpp | 15 +++++++++++++++ 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index e69b78659f5..4acb370fac6 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -900,9 +900,16 @@ bool extractForLoopValues(const Token *forToken, if (!initExpr || !initExpr->isBinaryOp() || initExpr->str() != "=" || !Token::Match(initExpr->astOperand1(), "%var%")) return false; std::vector minInitValue = getMinValue(ValueFlow::makeIntegralInferModel(), initExpr->astOperand2()->values()); + if (minInitValue.empty()) { + const ValueFlow::Value* v = initExpr->astOperand2()->getMinValue(true); + if (v) + minInitValue.push_back(v->intvalue); + } + if (minInitValue.empty()) + return false; varid = initExpr->astOperand1()->varId(); knownInitValue = initExpr->astOperand2()->hasKnownIntValue(); - initValue = minInitValue.empty() ? 0 : minInitValue.front(); + initValue = minInitValue.front(); partialCond = Token::Match(condExpr, "%oror%|&&"); visitAstNodes(condExpr, [varid, &condExpr](const Token *tok) { if (Token::Match(tok, "%oror%|&&")) diff --git a/lib/token.cpp b/lib/token.cpp index 0e9184626f3..a1d2cfd6f1c 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -2415,25 +2415,40 @@ const ValueFlow::Value* Token::getValue(const MathLib::bigint val) const return it == mImpl->mValues->end() ? nullptr : &*it; } -const ValueFlow::Value* Token::getMaxValue(bool condition, MathLib::bigint path) const +template +static const ValueFlow::Value* getCompareValue(const std::list& values, + bool condition, + MathLib::bigint path, + Compare compare) { - if (!mImpl->mValues) - return nullptr; const ValueFlow::Value* ret = nullptr; - for (const ValueFlow::Value& value : *mImpl->mValues) { + for (const ValueFlow::Value& value : values) { if (!value.isIntValue()) continue; if (value.isImpossible()) continue; if (path > -0 && value.path != 0 && value.path != path) continue; - if ((!ret || value.intvalue > ret->intvalue) && - ((value.condition != nullptr) == condition)) + if ((!ret || compare(value.intvalue, ret->intvalue)) && ((value.condition != nullptr) == condition)) ret = &value; } return ret; } +const ValueFlow::Value* Token::getMaxValue(bool condition, MathLib::bigint path) const +{ + if (!mImpl->mValues) + return nullptr; + return getCompareValue(*mImpl->mValues, condition, path, std::greater{}); +} + +const ValueFlow::Value* Token::getMinValue(bool condition, MathLib::bigint path) const +{ + if (!mImpl->mValues) + return nullptr; + return getCompareValue(*mImpl->mValues, condition, path, std::less{}); +} + const ValueFlow::Value* Token::getMovedValue() const { if (!mImpl->mValues) diff --git a/lib/token.h b/lib/token.h index d04d365d445..4163ab754c6 100644 --- a/lib/token.h +++ b/lib/token.h @@ -1224,6 +1224,7 @@ class CPPCHECKLIB Token { const ValueFlow::Value* getValue(const MathLib::bigint val) const; const ValueFlow::Value* getMaxValue(bool condition, MathLib::bigint path = 0) const; + const ValueFlow::Value* getMinValue(bool condition, MathLib::bigint path = 0) const; const ValueFlow::Value* getMovedValue() const; diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index 862add41981..17a0898bd85 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -190,6 +190,7 @@ class TestBufferOverrun : public TestFixture { TEST_CASE(array_index_negative7); // #5685 TEST_CASE(array_index_negative8); // #11651 TEST_CASE(array_index_negative9); + TEST_CASE(array_index_negative10); TEST_CASE(array_index_for_decr); TEST_CASE(array_index_varnames); // FP: struct member #1576, FN: #1586 TEST_CASE(array_index_for_continue); // for,continue @@ -2336,6 +2337,20 @@ class TestBufferOverrun : public TestFixture { ASSERT_EQUALS("[test.cpp:8]: (error) Array 'a[3]' accessed at index -1, which is out of bounds.\n", errout.str()); } + // #11844 + void array_index_negative10() + { + check("struct S { int a[4]; };\n" + "void f(S* p, int k) {\n" + " int m = 3;\n" + " if (k)\n" + " m = 2;\n" + " for (int j = m + 1; j <= 4; j++)\n" + " p->a[j-1];\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } + void array_index_for_decr() { check("void f()\n" "{\n" From 824f89514ada6cd6d95279c9f425d053e4da90da Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 14 Aug 2023 17:25:00 +0200 Subject: [PATCH 13/30] Add test for #10350, fix arg direction in windows.cfg (#5328) --- cfg/windows.cfg | 18 +++++++++--------- test/testother.cpp | 6 ++++++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/cfg/windows.cfg b/cfg/windows.cfg index 105ee469b56..53dc335e463 100644 --- a/cfg/windows.cfg +++ b/cfg/windows.cfg @@ -2176,7 +2176,7 @@ false - + @@ -3432,7 +3432,7 @@ HFONT CreateFont( - + @@ -3487,7 +3487,7 @@ HFONT CreateFont( - + @@ -3501,7 +3501,7 @@ HFONT CreateFont( false - + @@ -4726,7 +4726,7 @@ HFONT CreateFont( - + @@ -4806,7 +4806,7 @@ HFONT CreateFont( true - + @@ -4821,7 +4821,7 @@ HFONT CreateFont( false - + @@ -5646,7 +5646,7 @@ HFONT CreateFont( - + @@ -6791,7 +6791,7 @@ HFONT CreateFont( - + diff --git a/test/testother.cpp b/test/testother.cpp index 1d351ec342a..3e072aed436 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -11291,6 +11291,12 @@ class TestOther : public TestFixture { "}"); ASSERT_EQUALS("", errout.str()); + check("_Bool a[10];\n" // #10350 + "void foo() {\n" + " memcpy(&a[5], &a[4], 2u * sizeof(a[0]));\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (error) Overlapping read/write in memcpy() is undefined behavior\n", errout.str()); + // wmemcpy check("void foo() {\n" " wchar_t a[10];\n" From 8b309a882941f5960793413b3a4af192d3e0ef3e Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 16 Aug 2023 10:20:53 +0200 Subject: [PATCH 14/30] Use readdir() instead of deprecated readdir_r() (#5330) --- cli/filelister.cpp | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/cli/filelister.cpp b/cli/filelister.cpp index c83b3756967..59a6028653b 100644 --- a/cli/filelister.cpp +++ b/cli/filelister.cpp @@ -192,29 +192,10 @@ static std::string addFiles2(std::map &files, if (!dir) return ""; - dirent * dir_result; - // make sure we reserve enough space for the readdir_r() buffer; - // according to POSIX: - // The storage pointed to by entry shall be large enough for a - // dirent with an array of char d_name members containing at - // least {NAME_MAX}+1 elements. - // on some platforms, d_name is not a static sized-array but - // a pointer to space usually reserved right after the dirent - // struct; the union here allows to reserve the space and to - // provide a pointer to the right type that can be passed where - // needed without casts - union { - dirent entry; - char buf[sizeof(*dir_result) + (sizeof(dir_result->d_name) > 1 ? 0 : NAME_MAX + 1)]; - } dir_result_buffer; - // TODO: suppress instead? - (void)dir_result_buffer.buf; // do not trigger cppcheck itself on the "unused buf" - std::string new_path; - new_path.reserve(path.length() + 1 + sizeof(dir_result->d_name));// prealloc some memory to avoid constant new/deletes in loop - new_path += path; + std::string new_path = path; new_path += '/'; - while ((SUPPRESS_DEPRECATED_WARNING(readdir_r(dir, &dir_result_buffer.entry, &dir_result)) == 0) && (dir_result != nullptr)) { + while (const struct dirent* dir_result = readdir(dir)) { if ((std::strcmp(dir_result->d_name, ".") == 0) || (std::strcmp(dir_result->d_name, "..") == 0)) continue; From 6a263ba026cde4efee734195a96ae0b2ca0bbcb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Wed, 16 Aug 2023 11:10:38 +0200 Subject: [PATCH 15/30] optimized `Library::detectContainerInternal()` a bit (#5333) Scanning `cli/filelister.cpp` with `DISABLE_VALUEFLOW=1` and `--enable=all -Ilib -D__GNUC__` Clang 15 `111,300,996` -> `106,883,955` GCC 13 `110,555,879` -> `105,983,608` --- lib/library.cpp | 42 +++++++++++++++++++++++++----------------- lib/library.h | 2 +- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/lib/library.cpp b/lib/library.cpp index 4142dcd8ae1..15d64917113 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -419,7 +419,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc) const char* const inherits = node->Attribute("inherits"); if (inherits) { - const std::map::const_iterator i = containers.find(inherits); + const std::unordered_map::const_iterator i = containers.find(inherits); if (i != containers.end()) container = i->second; // Take values from parent and overwrite them if necessary else @@ -1158,8 +1158,17 @@ bool Library::isScopeNoReturn(const Token *end, std::string *unknownFunc) const return false; } -const Library::Container* Library::detectContainerInternal(const Token* typeStart, DetectContainer detect, bool* isIterator, bool withoutStd) const +const Library::Container* Library::detectContainerInternal(const Token* const typeStart, DetectContainer detect, bool* isIterator, bool withoutStd) const { + const Token* firstLinkedTok = nullptr; + for (const Token* tok = typeStart; tok && !tok->varId(); tok = tok->next()) { + if (!tok->link()) + continue; + + firstLinkedTok = tok; + break; + } + for (const std::pair & c : containers) { const Container& container = c.second; if (container.startPattern.empty()) @@ -1177,23 +1186,22 @@ const Library::Container* Library::detectContainerInternal(const Token* typeStar return &container; } - for (const Token* tok = typeStart; tok && !tok->varId(); tok = tok->next()) { - if (!tok->link()) - continue; + if (!firstLinkedTok) + continue; - const bool matchedStartPattern = Token::Match(typeStart, container.startPattern2.c_str() + offset); + const bool matchedStartPattern = Token::Match(typeStart, container.startPattern2.c_str() + offset); + if (!matchedStartPattern) + continue; - if (detect != ContainerOnly && matchedStartPattern && Token::Match(tok->link(), container.itEndPattern.c_str())) { - if (isIterator) - *isIterator = true; - return &container; - } - if (detect != IteratorOnly && matchedStartPattern && Token::Match(tok->link(), container.endPattern.c_str())) { - if (isIterator) - *isIterator = false; - return &container; - } - break; + if (detect != ContainerOnly && Token::Match(firstLinkedTok->link(), container.itEndPattern.c_str())) { + if (isIterator) + *isIterator = true; + return &container; + } + if (detect != IteratorOnly && Token::Match(firstLinkedTok->link(), container.endPattern.c_str())) { + if (isIterator) + *isIterator = false; + return &container; } } return nullptr; diff --git a/lib/library.h b/lib/library.h index 300382d9fc7..9c1b060f9ac 100644 --- a/lib/library.h +++ b/lib/library.h @@ -282,7 +282,7 @@ class CPPCHECKLIB Library { static Yield yieldFrom(const std::string& yieldName); static Action actionFrom(const std::string& actionName); }; - std::map containers; + std::unordered_map containers; const Container* detectContainer(const Token* typeStart) const; const Container* detectIterator(const Token* typeStart) const; const Container* detectContainerOrIterator(const Token* typeStart, bool* isIterator = nullptr, bool withoutStd = false) const; From 84a9b3a5f2aa743d3168ab7dfdfa889d23593ddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Wed, 16 Aug 2023 17:13:36 +0200 Subject: [PATCH 16/30] enabled and mitigated `modernize-use-equals-default` clang-tidy warnings / removed unnecessary default destructors (#5335) --- .clang-tidy | 1 - clang-tidy.md | 1 - cli/executor.cpp | 3 --- cli/executor.h | 2 +- cli/processexecutor.cpp | 3 --- cli/processexecutor.h | 1 - cli/singleexecutor.cpp | 3 --- cli/singleexecutor.h | 1 - cli/threadexecutor.cpp | 3 --- cli/threadexecutor.h | 1 - gui/application.h | 2 +- gui/checkthread.cpp | 9 +-------- gui/checkthread.h | 1 - gui/codeeditstylecontrols.h | 2 -- gui/codeeditstyledialog.h | 1 - gui/cppchecklibrarydata.cpp | 3 --- gui/cppchecklibrarydata.h | 2 +- gui/csvreport.cpp | 3 --- gui/csvreport.h | 1 - gui/printablereport.cpp | 3 --- gui/printablereport.h | 1 - gui/resultstree.cpp | 3 --- gui/resultstree.h | 2 +- gui/test/projectfile/testprojectfile.cpp | 4 ++-- gui/threadresult.cpp | 5 ----- gui/threadresult.h | 1 - gui/translationhandler.cpp | 3 --- gui/translationhandler.h | 1 - gui/txtreport.cpp | 3 --- gui/txtreport.h | 1 - lib/analyzer.h | 2 +- lib/check.h | 4 ++-- lib/ctu.h | 2 +- lib/errorlogger.h | 4 ++-- lib/infer.h | 2 +- lib/templatesimplifier.cpp | 3 --- lib/templatesimplifier.h | 1 - lib/timer.h | 4 ++-- lib/valueflow.cpp | 4 ++-- lib/valueptr.h | 1 - test/fixture.h | 1 - 41 files changed, 18 insertions(+), 80 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index e1bae2cd255..540d5a7e878 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -45,7 +45,6 @@ Checks: > -modernize-replace-auto-ptr, -modernize-return-braced-init-list, -modernize-use-auto, - -modernize-use-equals-default, -modernize-use-trailing-return-type, -performance-avoid-endl, -performance-inefficient-string-concatenation, diff --git a/clang-tidy.md b/clang-tidy.md index 2311d2d3a97..a2e2dd5db5e 100644 --- a/clang-tidy.md +++ b/clang-tidy.md @@ -63,7 +63,6 @@ This does not appear to be useful as it is reported on very common code. It was decided not to apply these. -`modernize-use-equals-default`
`modernize-loop-convert`
These might change the behavior of code which might not be intended (need to file an upstream issue) diff --git a/cli/executor.cpp b/cli/executor.cpp index 489d9f8951b..c7955d71704 100644 --- a/cli/executor.cpp +++ b/cli/executor.cpp @@ -31,9 +31,6 @@ Executor::Executor(const std::map &files, const Settin : mFiles(files), mSettings(settings), mSuppressions(suppressions), mErrorLogger(errorLogger) {} -Executor::~Executor() -{} - bool Executor::hasToLog(const ErrorMessage &msg) { if (!mSuppressions.isSuppressed(msg)) diff --git a/cli/executor.h b/cli/executor.h index 1b7db25e71e..8c67c6cfedd 100644 --- a/cli/executor.h +++ b/cli/executor.h @@ -40,7 +40,7 @@ class Suppressions; class Executor { public: Executor(const std::map &files, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger); - virtual ~Executor(); + virtual ~Executor() = default; Executor(const Executor &) = delete; void operator=(const Executor &) = delete; diff --git a/cli/processexecutor.cpp b/cli/processexecutor.cpp index 0bec1734e90..566e503eb32 100644 --- a/cli/processexecutor.cpp +++ b/cli/processexecutor.cpp @@ -67,9 +67,6 @@ ProcessExecutor::ProcessExecutor(const std::map &files assert(mSettings.jobs > 1); } -ProcessExecutor::~ProcessExecutor() -{} - class PipeWriter : public ErrorLogger { public: enum PipeSignal {REPORT_OUT='1',REPORT_ERROR='2', CHILD_END='5'}; diff --git a/cli/processexecutor.h b/cli/processexecutor.h index 4b51d596acc..580c344cfae 100644 --- a/cli/processexecutor.h +++ b/cli/processexecutor.h @@ -40,7 +40,6 @@ class ProcessExecutor : public Executor { public: ProcessExecutor(const std::map &files, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger); ProcessExecutor(const ProcessExecutor &) = delete; - ~ProcessExecutor() override; void operator=(const ProcessExecutor &) = delete; unsigned int check() override; diff --git a/cli/singleexecutor.cpp b/cli/singleexecutor.cpp index c3fea886b24..c52c984d996 100644 --- a/cli/singleexecutor.cpp +++ b/cli/singleexecutor.cpp @@ -37,9 +37,6 @@ SingleExecutor::SingleExecutor(CppCheck &cppcheck, const std::map &files, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger); SingleExecutor(const SingleExecutor &) = delete; - ~SingleExecutor() override; void operator=(const SingleExecutor &) = delete; unsigned int check() override; diff --git a/cli/threadexecutor.cpp b/cli/threadexecutor.cpp index a6a9e671bd0..96f35ac4015 100644 --- a/cli/threadexecutor.cpp +++ b/cli/threadexecutor.cpp @@ -46,9 +46,6 @@ ThreadExecutor::ThreadExecutor(const std::map &files, assert(mSettings.jobs > 1); } -ThreadExecutor::~ThreadExecutor() -{} - class SyncLogForwarder : public ErrorLogger { public: diff --git a/cli/threadexecutor.h b/cli/threadexecutor.h index 62ad8e0a860..8ebae323b5b 100644 --- a/cli/threadexecutor.h +++ b/cli/threadexecutor.h @@ -40,7 +40,6 @@ class ThreadExecutor : public Executor { public: ThreadExecutor(const std::map &files, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger); ThreadExecutor(const ThreadExecutor &) = delete; - ~ThreadExecutor() override; void operator=(const ThreadExecutor &) = delete; unsigned int check() override; diff --git a/gui/application.h b/gui/application.h index ee624bf07cd..a5bbc31a323 100644 --- a/gui/application.h +++ b/gui/application.h @@ -42,7 +42,7 @@ */ class Application { public: - Application() {} + Application() = default; Application(QString name, QString path, QString params); /** diff --git a/gui/checkthread.cpp b/gui/checkthread.cpp index b45f30c6eb0..0a8fbf34631 100644 --- a/gui/checkthread.cpp +++ b/gui/checkthread.cpp @@ -86,14 +86,7 @@ static bool executeCommand(std::string exe, std::vector args, std:: CheckThread::CheckThread(ThreadResult &result) : mResult(result), mCppcheck(result, true, executeCommand) -{ - //ctor -} - -CheckThread::~CheckThread() -{ - //dtor -} +{} void CheckThread::check(const Settings &settings) { diff --git a/gui/checkthread.h b/gui/checkthread.h index d74ec2514a9..65b6f782061 100644 --- a/gui/checkthread.h +++ b/gui/checkthread.h @@ -46,7 +46,6 @@ class CheckThread : public QThread { Q_OBJECT public: explicit CheckThread(ThreadResult &result); - ~CheckThread() override; /** * @brief Set settings for cppcheck diff --git a/gui/codeeditstylecontrols.h b/gui/codeeditstylecontrols.h index 7e87c7b5fc0..7285598ad73 100644 --- a/gui/codeeditstylecontrols.h +++ b/gui/codeeditstylecontrols.h @@ -35,7 +35,6 @@ class SelectColorButton : public QPushButton { Q_OBJECT public: explicit SelectColorButton(QWidget* parent); - ~SelectColorButton() override {} void setColor(const QColor& color); const QColor& getColor(); @@ -57,7 +56,6 @@ class SelectFontWeightCombo : public QComboBox { Q_OBJECT public: explicit SelectFontWeightCombo(QWidget* parent); - ~SelectFontWeightCombo() override {} void setWeight(const QFont::Weight& weight); const QFont::Weight& getWeight(); diff --git a/gui/codeeditstyledialog.h b/gui/codeeditstyledialog.h index 9ef42907be4..c4aeffc99e8 100644 --- a/gui/codeeditstyledialog.h +++ b/gui/codeeditstyledialog.h @@ -42,7 +42,6 @@ class StyleEditDialog : public QDialog { public: explicit StyleEditDialog(const CodeEditorStyle& newStyle, QWidget *parent = nullptr); - ~StyleEditDialog() override {} CodeEditorStyle getStyle(); diff --git a/gui/cppchecklibrarydata.cpp b/gui/cppchecklibrarydata.cpp index 2e7761a6534..83fe76622f6 100644 --- a/gui/cppchecklibrarydata.cpp +++ b/gui/cppchecklibrarydata.cpp @@ -35,9 +35,6 @@ const unsigned int CppcheckLibraryData::Function::Arg::ANY = ~0U; const unsigned int CppcheckLibraryData::Function::Arg::VARIADIC = ~1U; -CppcheckLibraryData::CppcheckLibraryData() -{} - static std::string unhandledElement(const QXmlStreamReader &xmlReader) { throw std::runtime_error(QObject::tr("line %1: Unhandled element %2").arg(xmlReader.lineNumber()).arg(xmlReader.name().toString()).toStdString()); diff --git a/gui/cppchecklibrarydata.h b/gui/cppchecklibrarydata.h index 252d66920ba..07fc2a81107 100644 --- a/gui/cppchecklibrarydata.h +++ b/gui/cppchecklibrarydata.h @@ -30,7 +30,7 @@ class QIODevice; class CppcheckLibraryData { public: - CppcheckLibraryData(); + CppcheckLibraryData() = default; struct Container { QString id; diff --git a/gui/csvreport.cpp b/gui/csvreport.cpp index 36da50bbde5..740651cf06f 100644 --- a/gui/csvreport.cpp +++ b/gui/csvreport.cpp @@ -30,9 +30,6 @@ CsvReport::CsvReport(const QString &filename) : Report(filename) {} -CsvReport::~CsvReport() -{} - bool CsvReport::create() { if (Report::create()) { diff --git a/gui/csvreport.h b/gui/csvreport.h index a2efdd93b0a..cfd918fe082 100644 --- a/gui/csvreport.h +++ b/gui/csvreport.h @@ -39,7 +39,6 @@ class ErrorItem; class CsvReport : public Report { public: explicit CsvReport(const QString &filename); - ~CsvReport() override; /** * @brief Create the report (file). diff --git a/gui/printablereport.cpp b/gui/printablereport.cpp index 9bcfff55c34..d9272632f45 100644 --- a/gui/printablereport.cpp +++ b/gui/printablereport.cpp @@ -27,9 +27,6 @@ PrintableReport::PrintableReport() : Report(QString()) {} -PrintableReport::~PrintableReport() -{} - bool PrintableReport::create() { return true; diff --git a/gui/printablereport.h b/gui/printablereport.h index 29fa008bf61..693356a961d 100644 --- a/gui/printablereport.h +++ b/gui/printablereport.h @@ -36,7 +36,6 @@ class ErrorItem; class PrintableReport : public Report { public: PrintableReport(); - ~PrintableReport() override; /** * @brief Create the report (file). diff --git a/gui/resultstree.cpp b/gui/resultstree.cpp index 61f995e6bf4..d94223dad78 100644 --- a/gui/resultstree.cpp +++ b/gui/resultstree.cpp @@ -91,9 +91,6 @@ ResultsTree::ResultsTree(QWidget * parent) : connect(this, &ResultsTree::doubleClicked, this, &ResultsTree::quickStartApplication); } -ResultsTree::~ResultsTree() -{} - void ResultsTree::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { diff --git a/gui/resultstree.h b/gui/resultstree.h index 5828c0e383b..8a8a79642b4 100644 --- a/gui/resultstree.h +++ b/gui/resultstree.h @@ -53,7 +53,7 @@ class ResultsTree : public QTreeView { Q_OBJECT public: explicit ResultsTree(QWidget * parent = nullptr); - ~ResultsTree() override; + void initialize(QSettings *settings, ApplicationList *list, ThreadHandler *checkThreadHandler); /** diff --git a/gui/test/projectfile/testprojectfile.cpp b/gui/test/projectfile/testprojectfile.cpp index cbd98dc86ca..65531aa0fa3 100644 --- a/gui/test/projectfile/testprojectfile.cpp +++ b/gui/test/projectfile/testprojectfile.cpp @@ -40,8 +40,8 @@ const char Settings::SafeChecks::XmlExternalFunctions[] = "external-functions"; const char Settings::SafeChecks::XmlInternalFunctions[] = "internal-functions"; const char Settings::SafeChecks::XmlExternalVariables[] = "external-variables"; Settings::Settings() : maxCtuDepth(10) {} -cppcheck::Platform::Platform() {} -ImportProject::ImportProject() {} +cppcheck::Platform::Platform() = default; +ImportProject::ImportProject() = default; bool ImportProject::sourceFileExists(const std::string & /*file*/) { return true; } diff --git a/gui/threadresult.cpp b/gui/threadresult.cpp index 5e1aed89b78..52d683414a8 100644 --- a/gui/threadresult.cpp +++ b/gui/threadresult.cpp @@ -28,11 +28,6 @@ #include #include -ThreadResult::~ThreadResult() -{ - //dtor -} - void ThreadResult::reportOut(const std::string &outmsg, Color /*c*/) { emit log(QString::fromStdString(outmsg)); diff --git a/gui/threadresult.h b/gui/threadresult.h index f08bb945230..4e32a1cbef2 100644 --- a/gui/threadresult.h +++ b/gui/threadresult.h @@ -46,7 +46,6 @@ class ThreadResult : public QObject, public ErrorLogger { Q_OBJECT public: ThreadResult() = default; - ~ThreadResult() override; /** * @brief Get next unprocessed file diff --git a/gui/translationhandler.cpp b/gui/translationhandler.cpp index 6b14b6241fb..2e17148fd2a 100644 --- a/gui/translationhandler.cpp +++ b/gui/translationhandler.cpp @@ -62,9 +62,6 @@ TranslationHandler::TranslationHandler(QObject *parent) : addTranslation("Swedish", "cppcheck_sv"); } -TranslationHandler::~TranslationHandler() -{} - bool TranslationHandler::setLanguage(const QString &code) { bool failure = false; diff --git a/gui/translationhandler.h b/gui/translationhandler.h index e9ff8722058..cd298d6ebaf 100644 --- a/gui/translationhandler.h +++ b/gui/translationhandler.h @@ -63,7 +63,6 @@ class TranslationHandler : QObject { Q_OBJECT public: explicit TranslationHandler(QObject *parent = nullptr); - ~TranslationHandler() override; /** * @brief Get a list of available translations. diff --git a/gui/txtreport.cpp b/gui/txtreport.cpp index 1be3944341c..caa3833ef8d 100644 --- a/gui/txtreport.cpp +++ b/gui/txtreport.cpp @@ -29,9 +29,6 @@ TxtReport::TxtReport(const QString &filename) : Report(filename) {} -TxtReport::~TxtReport() -{} - bool TxtReport::create() { if (Report::create()) { diff --git a/gui/txtreport.h b/gui/txtreport.h index 02395cc4484..d3e74f93d7c 100644 --- a/gui/txtreport.h +++ b/gui/txtreport.h @@ -40,7 +40,6 @@ class TxtReport : public Report { public: explicit TxtReport(const QString &filename); - ~TxtReport() override; /** * @brief Create the report (file). diff --git a/lib/analyzer.h b/lib/analyzer.h index 3c65e0e68de..3ceab711b32 100644 --- a/lib/analyzer.h +++ b/lib/analyzer.h @@ -184,7 +184,7 @@ struct Analyzer { virtual bool invalid() const { return false; } - virtual ~Analyzer() {} + virtual ~Analyzer() = default; Analyzer(const Analyzer&) = default; protected: Analyzer() = default; diff --git a/lib/check.h b/lib/check.h index 39e34781505..8e8e764637c 100644 --- a/lib/check.h +++ b/lib/check.h @@ -100,8 +100,8 @@ class CPPCHECKLIB Check { /** Base class used for whole-program analysis */ class CPPCHECKLIB FileInfo { public: - FileInfo() {} - virtual ~FileInfo() {} + FileInfo() = default; + virtual ~FileInfo() = default; virtual std::string toString() const { return std::string(); } diff --git a/lib/ctu.h b/lib/ctu.h index a353ac1d7d7..7fdd0f09360 100644 --- a/lib/ctu.h +++ b/lib/ctu.h @@ -82,7 +82,7 @@ namespace CTU { : callId(std::move(callId)), callArgNr(callArgNr), callFunctionName(std::move(callFunctionName)), location(std::move(loc)) {} CallBase(const Tokenizer *tokenizer, const Token *callToken); - virtual ~CallBase() {} + virtual ~CallBase() = default; CallBase(const CallBase&) = default; std::string callId; int callArgNr{}; diff --git a/lib/errorlogger.h b/lib/errorlogger.h index ef8d8a71937..4cb1352c2c1 100644 --- a/lib/errorlogger.h +++ b/lib/errorlogger.h @@ -219,8 +219,8 @@ class CPPCHECKLIB ErrorMessage { */ class CPPCHECKLIB ErrorLogger { public: - ErrorLogger() {} - virtual ~ErrorLogger() {} + ErrorLogger() = default; + virtual ~ErrorLogger() = default; /** * Information about progress is directed here. diff --git a/lib/infer.h b/lib/infer.h index 21ffcb22c25..35d2afb1822 100644 --- a/lib/infer.h +++ b/lib/infer.h @@ -33,7 +33,7 @@ template class ValuePtr; struct InferModel { virtual bool match(const ValueFlow::Value& value) const = 0; virtual ValueFlow::Value yield(MathLib::bigint value) const = 0; - virtual ~InferModel() {} + virtual ~InferModel() = default; InferModel(const InferModel&) = default; protected: InferModel() = default; diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index e551790a461..dbd80226941 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -284,9 +284,6 @@ TemplateSimplifier::TemplateSimplifier(Tokenizer &tokenizer) mErrorLogger(mTokenizer.mErrorLogger) {} -TemplateSimplifier::~TemplateSimplifier() -{} - void TemplateSimplifier::checkComplicatedSyntaxErrorsInTemplates() { // check for more complicated syntax errors when using templates.. diff --git a/lib/templatesimplifier.h b/lib/templatesimplifier.h index 763962ea24c..29b78fb8409 100644 --- a/lib/templatesimplifier.h +++ b/lib/templatesimplifier.h @@ -48,7 +48,6 @@ class CPPCHECKLIB TemplateSimplifier { public: explicit TemplateSimplifier(Tokenizer &tokenizer); - ~TemplateSimplifier(); std::string dump() const { return mDump; diff --git a/lib/timer.h b/lib/timer.h index 1fe246f417d..34a5216d8d3 100644 --- a/lib/timer.h +++ b/lib/timer.h @@ -37,7 +37,7 @@ enum class SHOWTIME_MODES { class CPPCHECKLIB TimerResultsIntf { public: - virtual ~TimerResultsIntf() {} + virtual ~TimerResultsIntf() = default; virtual void addResults(const std::string& str, std::clock_t clocks) = 0; }; @@ -54,7 +54,7 @@ struct TimerResultsData { class CPPCHECKLIB TimerResults : public TimerResultsIntf { public: - TimerResults() {} + TimerResults() = default; void showResults(SHOWTIME_MODES mode) const; void addResults(const std::string& str, std::clock_t clocks) override; diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index c6ba15f6855..1a280f9d845 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -6676,7 +6676,7 @@ struct ConditionHandler { } }); } - virtual ~ConditionHandler() {} + virtual ~ConditionHandler() = default; ConditionHandler(const ConditionHandler&) = default; protected: ConditionHandler() = default; @@ -9291,7 +9291,7 @@ struct ValueFlowPass { virtual void run(const ValueFlowState& state) const = 0; // Returns true if pass needs C++ virtual bool cpp() const = 0; - virtual ~ValueFlowPass() noexcept {} + virtual ~ValueFlowPass() noexcept = default; }; struct ValueFlowPassRunner { diff --git a/lib/valueptr.h b/lib/valueptr.h index 0740a72fc10..3bb3f71e260 100644 --- a/lib/valueptr.h +++ b/lib/valueptr.h @@ -97,7 +97,6 @@ class CPPCHECKLIB ValuePtr { operator bool() const NOEXCEPT { return !!mPtr; } - ~ValuePtr() {} private: std::shared_ptr mPtr; diff --git a/test/fixture.h b/test/fixture.h index f641f09bdee..24633132d3d 100644 --- a/test/fixture.h +++ b/test/fixture.h @@ -241,7 +241,6 @@ class TestFixture : public ErrorLogger { const std::string classname; explicit TestFixture(const char * const _name); - ~TestFixture() override {} static std::size_t runTests(const options& args); }; From d8b44dff56be3a772c395fab39beaf9e15efc21a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Wed, 16 Aug 2023 19:35:53 +0200 Subject: [PATCH 17/30] fixed/suppressed several compiler warnings (#5327) --- .github/workflows/CI-unixish.yml | 4 +++- .github/workflows/CI-windows.yml | 2 ++ Makefile | 6 +++--- cmake/compileroptions.cmake | 2 -- gui/resultstree.cpp | 10 +++++++++- lib/CMakeLists.txt | 13 ------------- lib/config.h | 25 ++++++++++++++++++------ lib/cppcheck.cpp | 5 ++--- lib/cppcheck.h | 3 --- lib/cppcheck.vcxproj | 3 ++- lib/importproject.cpp | 3 +-- lib/json.h | 33 ++++++++++++++++++++++++++++++++ lib/keywords.cpp | 6 ++++++ lib/lib.pri | 1 + lib/settings.cpp | 3 +-- lib/symboldatabase.cpp | 6 +++--- test/testmathlib.cpp | 12 ++++++++++-- tools/dmake.cpp | 1 + 18 files changed, 96 insertions(+), 42 deletions(-) create mode 100644 lib/json.h diff --git a/.github/workflows/CI-unixish.yml b/.github/workflows/CI-unixish.yml index 1e51f0d6faa..10cbf319d3d 100644 --- a/.github/workflows/CI-unixish.yml +++ b/.github/workflows/CI-unixish.yml @@ -85,6 +85,8 @@ jobs: sudo apt-get update sudo apt-get install libxml2-utils qtbase5-dev qttools5-dev libqt5charts5-dev qtchooser + # TODO: move latest compiler to separate step + # TODO: bail out on warnings with latest GCC - name: Set up GCC uses: egor-tensin/setup-gcc@v1 if: matrix.os == 'ubuntu-22.04' @@ -93,9 +95,9 @@ jobs: platform: x64 - name: Select compiler + if: matrix.os == 'ubuntu-22.04' run: | echo "CXX=g++-13" >> $GITHUB_ENV - if: matrix.os == 'ubuntu-22.04' # coreutils contains "nproc" - name: Install missing software on macos diff --git a/.github/workflows/CI-windows.yml b/.github/workflows/CI-windows.yml index 4da98719ded..98df86f8558 100644 --- a/.github/workflows/CI-windows.yml +++ b/.github/workflows/CI-windows.yml @@ -13,6 +13,8 @@ defaults: run: shell: cmd +# TODO: choose/add a step to bail out on compiler warnings (maybe even the release build) + jobs: build_qt: diff --git a/Makefile b/Makefile index 6a2b1faad77..5d7931f9a94 100644 --- a/Makefile +++ b/Makefile @@ -545,7 +545,7 @@ $(libcppdir)/clangimport.o: lib/clangimport.cpp lib/clangimport.h lib/config.h l $(libcppdir)/color.o: lib/color.cpp lib/color.h lib/config.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/color.cpp -$(libcppdir)/cppcheck.o: lib/cppcheck.cpp externals/picojson/picojson.h externals/simplecpp/simplecpp.h externals/tinyxml2/tinyxml2.h lib/analyzerinfo.h lib/check.h lib/checkunusedfunctions.h lib/clangimport.h lib/color.h lib/config.h lib/cppcheck.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.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 lib/version.h lib/vfvalue.h +$(libcppdir)/cppcheck.o: lib/cppcheck.cpp externals/picojson/picojson.h externals/simplecpp/simplecpp.h externals/tinyxml2/tinyxml2.h lib/analyzerinfo.h lib/check.h lib/checkunusedfunctions.h lib/clangimport.h lib/color.h lib/config.h lib/cppcheck.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.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 lib/version.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/cppcheck.cpp $(libcppdir)/ctu.o: lib/ctu.cpp externals/tinyxml2/tinyxml2.h lib/astutils.h lib/check.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h @@ -563,7 +563,7 @@ $(libcppdir)/forwardanalyzer.o: lib/forwardanalyzer.cpp lib/analyzer.h lib/astut $(libcppdir)/fwdanalysis.o: lib/fwdanalysis.cpp lib/astutils.h lib/config.h lib/errortypes.h lib/fwdanalysis.h lib/library.h lib/mathlib.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/fwdanalysis.cpp -$(libcppdir)/importproject.o: lib/importproject.cpp externals/picojson/picojson.h externals/simplecpp/simplecpp.h externals/tinyxml2/tinyxml2.h lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/importproject.o: lib/importproject.cpp externals/picojson/picojson.h externals/simplecpp/simplecpp.h externals/tinyxml2/tinyxml2.h lib/config.h lib/errortypes.h lib/importproject.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/importproject.cpp $(libcppdir)/infer.o: lib/infer.cpp lib/calculate.h lib/config.h lib/errortypes.h lib/infer.h lib/mathlib.h lib/valueptr.h lib/vfvalue.h @@ -599,7 +599,7 @@ $(libcppdir)/programmemory.o: lib/programmemory.cpp lib/astutils.h lib/calculate $(libcppdir)/reverseanalyzer.o: lib/reverseanalyzer.cpp lib/analyzer.h lib/astutils.h lib/config.h lib/errortypes.h lib/forwardanalyzer.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/reverseanalyzer.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueptr.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/reverseanalyzer.cpp -$(libcppdir)/settings.o: lib/settings.cpp externals/picojson/picojson.h lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/summaries.h lib/suppressions.h lib/timer.h lib/utils.h lib/vfvalue.h +$(libcppdir)/settings.o: lib/settings.cpp externals/picojson/picojson.h lib/config.h lib/errortypes.h lib/importproject.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/summaries.h lib/suppressions.h lib/timer.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/settings.cpp $(libcppdir)/summaries.o: lib/summaries.cpp lib/analyzerinfo.h lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/sourcelocation.h lib/standards.h lib/summaries.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h diff --git a/cmake/compileroptions.cmake b/cmake/compileroptions.cmake index e7d0a3bf787..4c5ad9af858 100644 --- a/cmake/compileroptions.cmake +++ b/cmake/compileroptions.cmake @@ -95,8 +95,6 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options_safe(-Wno-suggest-override) # TODO: enable when warnings are fixed in in tinyxml2 add_compile_options_safe(-Wno-suggest-destructor-override) # TODO: enable when warnings are fixed in in tinyxml2 add_compile_options_safe(-Wno-extra-semi-stmt) # TODO: enable when warnings are fixed in in tinyxml2 - add_compile_options_safe(-Wno-implicitly-unsigned-literal) - add_compile_options_safe(-Wno-tautological-type-limit-compare) add_compile_options(-Wno-disabled-macro-expansion) add_compile_options_safe(-Wno-bitwise-instead-of-logical) diff --git a/gui/resultstree.cpp b/gui/resultstree.cpp index d94223dad78..946437f9602 100644 --- a/gui/resultstree.cpp +++ b/gui/resultstree.cpp @@ -812,7 +812,15 @@ void ResultsTree::startApplication(QStandardItem *target, int application) const QString cmdLine = QString("%1 %2").arg(program).arg(params); // this is reported as deprecated in Qt 5.15.2 but no longer in Qt 6 - const bool success = SUPPRESS_DEPRECATED_WARNING(QProcess::startDetached(cmdLine)); +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + SUPPRESS_WARNING_CLANG_PUSH("-Wdeprecated") + SUPPRESS_WARNING_GCC_PUSH("-Wdeprecated-declarations") +#endif + const bool success = QProcess::startDetached(cmdLine); +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + SUPPRESS_WARNING_GCC_POP + SUPPRESS_WARNING_CLANG_POP +#endif if (!success) { QString text = tr("Could not start %1\n\nPlease check the application path and parameters are correct.").arg(program); diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 741e6c2adfc..e4332578a95 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -56,16 +56,3 @@ endif() if (NOT CMAKE_DISABLE_PRECOMPILE_HEADERS) target_precompile_headers(cppcheck-core PRIVATE precompiled.h) endif() - -if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - # -Wfloat-equal is generated by picojson.h - if (NOT USE_MATCHCOMPILER_OPT STREQUAL "Off") - set_source_files_properties(mc_cppcheck.cpp PROPERTIES COMPILE_FLAGS -Wno-float-equal) - set_source_files_properties(mc_importproject.cpp PROPERTIES COMPILE_FLAGS -Wno-float-equal) - set_source_files_properties(mc_settings.cpp PROPERTIES COMPILE_FLAGS -Wno-float-equal) - else() - set_source_files_properties(cppcheck.cpp PROPERTIES COMPILE_FLAGS -Wno-float-equal) - set_source_files_properties(importproject.cpp PROPERTIES COMPILE_FLAGS -Wno-float-equal) - set_source_files_properties(settings.cpp PROPERTIES COMPILE_FLAGS -Wno-float-equal) - endif() -endif() diff --git a/lib/config.h b/lib/config.h index 2f45debe005..d6ef3c37dc0 100644 --- a/lib/config.h +++ b/lib/config.h @@ -133,13 +133,26 @@ static const std::string emptyString; #define STRINGISIZE(...) #__VA_ARGS__ #ifdef __clang__ -#define SUPPRESS_WARNING(warning, ...)_Pragma("clang diagnostic push") _Pragma(STRINGISIZE(clang diagnostic ignored warning)) __VA_ARGS__ _Pragma("clang diagnostic pop") -#define SUPPRESS_DEPRECATED_WARNING(...) SUPPRESS_WARNING("-Wdeprecated", __VA_ARGS__) -#define SUPPRESS_FLOAT_EQUAL_WARNING(...) SUPPRESS_WARNING("-Wfloat-equal", __VA_ARGS__) +#define SUPPRESS_WARNING_PUSH(warning) _Pragma("clang diagnostic push") _Pragma(STRINGISIZE(clang diagnostic ignored warning)) +#define SUPPRESS_WARNING_POP _Pragma("clang diagnostic pop") +#define SUPPRESS_WARNING_GCC_PUSH(warning) +#define SUPPRESS_WARNING_GCC_POP +#define SUPPRESS_WARNING_CLANG_PUSH(warning) SUPPRESS_WARNING_PUSH(warning) +#define SUPPRESS_WARNING_CLANG_POP SUPPRESS_WARNING_POP +#elif defined(__GNUC__) +#define SUPPRESS_WARNING_PUSH(warning) _Pragma("GCC diagnostic push") _Pragma(STRINGISIZE(GCC diagnostic ignored warning)) +#define SUPPRESS_WARNING_POP _Pragma("GCC diagnostic pop") +#define SUPPRESS_WARNING_GCC_PUSH(warning) SUPPRESS_WARNING_PUSH(warning) +#define SUPPRESS_WARNING_GCC_POP SUPPRESS_WARNING_POP +#define SUPPRESS_WARNING_CLANG_PUSH(warning) +#define SUPPRESS_WARNING_CLANG_POP #else -#define SUPPRESS_WARNING(warning, ...) __VA_ARGS__ -#define SUPPRESS_DEPRECATED_WARNING(...) __VA_ARGS__ -#define SUPPRESS_FLOAT_EQUAL_WARNING(...) __VA_ARGS__ +#define SUPPRESS_WARNING_PUSH(warning) +#define SUPPRESS_WARNING_POP +#define SUPPRESS_WARNING_GCC_PUSH(warning) +#define SUPPRESS_WARNING_GCC_POP +#define SUPPRESS_WARNING_CLANG_PUSH(warning) +#define SUPPRESS_WARNING_CLANG_POP #endif #if !defined(NO_WINDOWS_SEH) && defined(_WIN32) && defined(_MSC_VER) diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 074e5ce71ca..67681de63b5 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -63,8 +63,7 @@ #include #endif -#define PICOJSON_USE_INT64 -#include +#include "json.h" #include @@ -940,7 +939,7 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string #ifdef HAVE_RULES // handling of "simple" rules has been removed. - if (mSimplify && hasRule("simple")) + if (hasRule("simple")) throw InternalError(nullptr, "Handling of \"simple\" rules has been removed in Cppcheck. Use --addon instead."); #endif diff --git a/lib/cppcheck.h b/lib/cppcheck.h index 925111ae75b..2de468d48ff 100644 --- a/lib/cppcheck.h +++ b/lib/cppcheck.h @@ -224,9 +224,6 @@ class CPPCHECKLIB CppCheck : ErrorLogger { /** Are there too many configs? */ bool mTooManyConfigs{}; - /** Simplify code? true by default */ - bool mSimplify = true; - /** File info used for whole program analysis */ std::list mFileInfo; diff --git a/lib/cppcheck.vcxproj b/lib/cppcheck.vcxproj index c64878713ba..28e4752d6b6 100644 --- a/lib/cppcheck.vcxproj +++ b/lib/cppcheck.vcxproj @@ -1,4 +1,4 @@ - + Debug-PCRE @@ -150,6 +150,7 @@ + diff --git a/lib/importproject.cpp b/lib/importproject.cpp index 76403ff40db..0537851a5d0 100644 --- a/lib/importproject.cpp +++ b/lib/importproject.cpp @@ -40,8 +40,7 @@ #include -#define PICOJSON_USE_INT64 -#include +#include "json.h" ImportProject::ImportProject() { diff --git a/lib/json.h b/lib/json.h new file mode 100644 index 00000000000..521d6b9c9cf --- /dev/null +++ b/lib/json.h @@ -0,0 +1,33 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2023 Cppcheck team. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef jsonH +#define jsonH + +SUPPRESS_WARNING_PUSH("-Wfloat-equal") +SUPPRESS_WARNING_CLANG_PUSH("-Wtautological-type-limit-compare") +SUPPRESS_WARNING_GCC_PUSH("-Wparentheses") + +#define PICOJSON_USE_INT64 +#include + +SUPPRESS_WARNING_GCC_POP +SUPPRESS_WARNING_CLANG_POP +SUPPRESS_WARNING_POP + +#endif // jsonH diff --git a/lib/keywords.cpp b/lib/keywords.cpp index 70fb2f6e341..87f1bef35d4 100644 --- a/lib/keywords.cpp +++ b/lib/keywords.cpp @@ -18,6 +18,8 @@ #include "keywords.h" +#include + // see https://en.cppreference.com/w/c/keyword #define C90_KEYWORDS \ @@ -162,6 +164,7 @@ const std::unordered_set& Keywords::getAll(Standards::cstd_t cStd) /*case Standards::cstd_t::C23: return c23_keywords_all;*/ } + assert(false && "unreachable"); } // cppcheck-suppress unusedFunction @@ -181,6 +184,7 @@ const std::unordered_set& Keywords::getAll(Standards::cppstd_t cppS case Standards::cppstd_t::CPP23: return cpp23_keywords_all; } + assert(false && "unreachable"); } // cppcheck-suppress unusedFunction @@ -197,6 +201,7 @@ const std::unordered_set& Keywords::getOnly(Standards::cstd_t cStd) /*case Standards::cstd_t::C23: return c23_keywords_all;*/ } + assert(false && "unreachable"); } // cppcheck-suppress unusedFunction @@ -217,5 +222,6 @@ const std::unordered_set& Keywords::getOnly(Standards::cppstd_t cpp case Standards::cppstd_t::CPP23: return cpp23_keywords; } + assert(false && "unreachable"); } diff --git a/lib/lib.pri b/lib/lib.pri index c6347fec6c6..09676f2dede 100644 --- a/lib/lib.pri +++ b/lib/lib.pri @@ -44,6 +44,7 @@ HEADERS += $${PWD}/analyzer.h \ $${PWD}/fwdanalysis.h \ $${PWD}/importproject.h \ $${PWD}/infer.h \ + $${PWD}/json.h \ $${PWD}/keywords.h \ $${PWD}/library.h \ $${PWD}/mathlib.h \ diff --git a/lib/settings.cpp b/lib/settings.cpp index 1efc55c9015..de7add238a8 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -24,8 +24,7 @@ #include -#define PICOJSON_USE_INT64 -#include +#include "json.h" std::atomic Settings::mTerminated; diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 4712e646ec8..37c9a5b003b 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -3025,21 +3025,21 @@ bool Function::returnsReference(const Function* function, bool unknown, bool inc bool Function::returnsPointer(const Function* function, bool unknown) { - return checkReturns(function, unknown, false, [](UNUSED const Token* defStart, const Token* defEnd) { + return checkReturns(function, unknown, false, [](const Token* /*defStart*/, const Token* defEnd) { return Token::simpleMatch(defEnd->previous(), "*"); }); } bool Function::returnsStandardType(const Function* function, bool unknown) { - return checkReturns(function, unknown, true, [](UNUSED const Token* defStart, const Token* defEnd) { + return checkReturns(function, unknown, true, [](const Token* /*defStart*/, const Token* defEnd) { return defEnd->previous() && defEnd->previous()->isStandardType(); }); } bool Function::returnsVoid(const Function* function, bool unknown) { - return checkReturns(function, unknown, true, [](UNUSED const Token* defStart, const Token* defEnd) { + return checkReturns(function, unknown, true, [](const Token* /*defStart*/, const Token* defEnd) { return Token::simpleMatch(defEnd->previous(), "void"); }); } diff --git a/test/testmathlib.cpp b/test/testmathlib.cpp index e49d08afa17..9a31110f1d2 100644 --- a/test/testmathlib.cpp +++ b/test/testmathlib.cpp @@ -382,6 +382,8 @@ class TestMathLib : public TestFixture { ASSERT_THROW_EQUALS(MathLib::toLongNumber("-02000000000000000000000"), InternalError, "Internal Error. MathLib::toLongNumber: out_of_range: -02000000000000000000000"); // min/max and out-of-bounds - decimal + SUPPRESS_WARNING_CLANG_PUSH("-Wimplicitly-unsigned-literal") + SUPPRESS_WARNING_GCC_PUSH("-Woverflow") { const MathLib::bigint i = 18446744073709551615; ASSERT_EQUALS(i, MathLib::toLongNumber(std::to_string(i))); @@ -392,8 +394,10 @@ class TestMathLib : public TestFixture { ASSERT_EQUALS(i, MathLib::toLongNumber(std::to_string(i))); ASSERT_EQUALS(i, MathLib::toLongNumber("-18446744073709551615")); } + SUPPRESS_WARNING_GCC_POP + SUPPRESS_WARNING_CLANG_POP - ASSERT_THROW_EQUALS(MathLib::toLongNumber("18446744073709551616"), InternalError, "Internal Error. MathLib::toLongNumber: out_of_range: 18446744073709551616"); + ASSERT_THROW_EQUALS(MathLib::toLongNumber("18446744073709551616"), InternalError, "Internal Error. MathLib::toLongNumber: out_of_range: 18446744073709551616"); ASSERT_THROW_EQUALS(MathLib::toLongNumber("-18446744073709551616"), InternalError, "Internal Error. MathLib::toLongNumber: out_of_range: -18446744073709551616"); ASSERT_THROW_EQUALS(MathLib::toLongNumber("invalid"), InternalError, "Internal Error. MathLib::toLongNumber: invalid_argument: invalid"); @@ -539,6 +543,8 @@ class TestMathLib : public TestFixture { ASSERT_THROW_EQUALS(MathLib::toULongNumber("-02000000000000000000000"), InternalError, "Internal Error. MathLib::toULongNumber: out_of_range: -02000000000000000000000"); // min/max and out-of-bounds - decimal + SUPPRESS_WARNING_CLANG_PUSH("-Wimplicitly-unsigned-literal") + SUPPRESS_WARNING_GCC_PUSH("-Woverflow") { const MathLib::biguint u = 18446744073709551615; ASSERT_EQUALS(u, MathLib::toULongNumber(std::to_string(u))); @@ -549,8 +555,10 @@ class TestMathLib : public TestFixture { ASSERT_EQUALS(u, MathLib::toULongNumber(std::to_string(u))); ASSERT_EQUALS(u, MathLib::toULongNumber("-18446744073709551615")); } + SUPPRESS_WARNING_GCC_POP + SUPPRESS_WARNING_CLANG_POP - ASSERT_THROW_EQUALS(MathLib::toULongNumber("18446744073709551616"), InternalError, "Internal Error. MathLib::toULongNumber: out_of_range: 18446744073709551616"); + ASSERT_THROW_EQUALS(MathLib::toULongNumber("18446744073709551616"), InternalError, "Internal Error. MathLib::toULongNumber: out_of_range: 18446744073709551616"); ASSERT_THROW_EQUALS(MathLib::toULongNumber("-18446744073709551616"), InternalError, "Internal Error. MathLib::toULongNumber: out_of_range: -18446744073709551616"); ASSERT_THROW_EQUALS(MathLib::toULongNumber("invalid"), InternalError, "Internal Error. MathLib::toULongNumber: invalid_argument: invalid"); diff --git a/tools/dmake.cpp b/tools/dmake.cpp index e2571fa8764..4c4c6fa1bbe 100644 --- a/tools/dmake.cpp +++ b/tools/dmake.cpp @@ -314,6 +314,7 @@ int main(int argc, char **argv) libfiles_h.emplace_back("analyzer.h"); libfiles_h.emplace_back("calculate.h"); libfiles_h.emplace_back("config.h"); + libfiles_h.emplace_back("json.h"); libfiles_h.emplace_back("precompiled.h"); libfiles_h.emplace_back("smallvector.h"); libfiles_h.emplace_back("standards.h"); From 3cf910019805ed9a3a5c8cc14870f0163df64da4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Thu, 17 Aug 2023 16:46:32 +0200 Subject: [PATCH 18/30] fixed #6316 (Use std::to_string() in place of MathLib::toString() ...) - deleted default implementation of `Mathlib::toString()` (#5341) It was also used inconsistently and seemed to imply there is some special handling which wasn't the case. It was just an alias for `std::to_string()` for non-`double` types. So there was no need for it. --------- Co-authored-by: Robert Reif --- lib/astutils.cpp | 2 +- lib/checkbufferoverrun.cpp | 14 +++++++------- lib/checkclass.cpp | 2 +- lib/checkcondition.cpp | 4 ++-- lib/checkother.cpp | 2 +- lib/checkstl.cpp | 12 ++++++------ lib/cppcheck.cpp | 4 ++-- lib/ctu.cpp | 4 ++-- lib/errorlogger.cpp | 16 ++++++++-------- lib/mathlib.cpp | 16 ++++++++-------- lib/mathlib.h | 6 ++---- lib/suppressions.cpp | 4 ++-- lib/symboldatabase.cpp | 2 +- lib/templatesimplifier.cpp | 10 +++++----- lib/token.cpp | 2 +- lib/tokenize.cpp | 24 ++++++++++++------------ lib/tokenlist.cpp | 6 +++--- lib/valueflow.cpp | 12 ++++++------ lib/vfvalue.cpp | 12 ++++++------ test/testgarbage.cpp | 2 +- test/testmathlib.cpp | 17 +++-------------- test/testvarid.cpp | 2 +- 22 files changed, 81 insertions(+), 94 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 4acb370fac6..397ad5337f6 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -341,7 +341,7 @@ static bool match(const Token *tok, const std::string &rhs) { if (tok->str() == rhs) return true; - if (!tok->varId() && tok->hasKnownIntValue() && MathLib::toString(tok->values().front().intvalue) == rhs) + if (!tok->varId() && tok->hasKnownIntValue() && std::to_string(tok->values().front().intvalue) == rhs) return true; return false; } diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index d0dbe95dacf..cf5ec86fd71 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -119,7 +119,7 @@ static int getMinFormatStringOutputLength(const std::vector ¶m i_d_x_f_found = true; parameterLength = 1; if (inputArgNr < parameters.size() && parameters[inputArgNr]->hasKnownIntValue()) - parameterLength = MathLib::toString(parameters[inputArgNr]->getKnownIntValue()).length(); + parameterLength = std::to_string(parameters[inputArgNr]->getKnownIntValue()).length(); handleNextParameter = true; break; @@ -362,7 +362,7 @@ void CheckBufferOverrun::arrayIndex() static std::string stringifyIndexes(const std::string& array, const std::vector& indexValues) { if (indexValues.size() == 1) - return MathLib::toString(indexValues[0].intvalue); + return std::to_string(indexValues[0].intvalue); std::ostringstream ret; ret << array; @@ -383,7 +383,7 @@ static std::string arrayIndexMessage(const Token* tok, const Token* condition) { auto add_dim = [](const std::string &s, const Dimension &dim) { - return s + "[" + MathLib::toString(dim.num) + "]"; + return s + "[" + std::to_string(dim.num) + "]"; }; const std::string array = std::accumulate(dimensions.cbegin(), dimensions.cend(), tok->astOperand1()->expressionString(), add_dim); @@ -528,7 +528,7 @@ void CheckBufferOverrun::pointerArithmeticError(const Token *tok, const Token *i std::string errmsg; if (indexValue->condition) - errmsg = "Undefined behaviour, when '" + indexToken->expressionString() + "' is " + MathLib::toString(indexValue->intvalue) + " the pointer arithmetic '" + tok->expressionString() + "' is out of bounds."; + errmsg = "Undefined behaviour, when '" + indexToken->expressionString() + "' is " + std::to_string(indexValue->intvalue) + " the pointer arithmetic '" + tok->expressionString() + "' is out of bounds."; else errmsg = "Undefined behaviour, pointer arithmetic '" + tok->expressionString() + "' is out of bounds."; @@ -992,13 +992,13 @@ bool CheckBufferOverrun::analyseWholeProgram1(const std::map 0) - errmsg = "Array index out of bounds; '" + unsafeUsage.myArgumentName + "' buffer size is " + MathLib::toString(functionCall->callArgValue) + " and it is accessed at offset " + MathLib::toString(unsafeUsage.value) + "."; + errmsg = "Array index out of bounds; '" + unsafeUsage.myArgumentName + "' buffer size is " + std::to_string(functionCall->callArgValue) + " and it is accessed at offset " + std::to_string(unsafeUsage.value) + "."; else - errmsg = "Array index out of bounds; buffer '" + unsafeUsage.myArgumentName + "' is accessed at offset " + MathLib::toString(unsafeUsage.value) + "."; + errmsg = "Array index out of bounds; buffer '" + unsafeUsage.myArgumentName + "' is accessed at offset " + std::to_string(unsafeUsage.value) + "."; cwe = (unsafeUsage.value > 0) ? CWE_BUFFER_OVERRUN : CWE_BUFFER_UNDERRUN; } else { errorId = "ctuPointerArith"; - errmsg = "Pointer arithmetic overflow; '" + unsafeUsage.myArgumentName + "' buffer size is " + MathLib::toString(functionCall->callArgValue); + errmsg = "Pointer arithmetic overflow; '" + unsafeUsage.myArgumentName + "' buffer size is " + std::to_string(functionCall->callArgValue); cwe = CWE_POINTER_ARITHMETIC_OVERFLOW; } diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 662a6707619..497babe1d60 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -2845,7 +2845,7 @@ void CheckClass::virtualFunctionCallInConstructorError( } reportError(errorPath, Severity::style, "virtualCallInConstructor", - "Virtual function '" + funcname + "' is called from " + scopeFunctionTypeName + " '" + constructorName + "' at line " + MathLib::toString(lineNumber) + ". Dynamic binding is not used.", CWE(0U), Certainty::normal); + "Virtual function '" + funcname + "' is called from " + scopeFunctionTypeName + " '" + constructorName + "' at line " + std::to_string(lineNumber) + ". Dynamic binding is not used.", CWE(0U), Certainty::normal); } void CheckClass::pureVirtualFunctionCallInConstructorError( diff --git a/lib/checkcondition.cpp b/lib/checkcondition.cpp index be1283232ea..2d018f1fb31 100644 --- a/lib/checkcondition.cpp +++ b/lib/checkcondition.cpp @@ -1039,7 +1039,7 @@ static bool parseComparison(const Token *comp, bool ¬1, std::string &op, std: return false; op = invertOperatorForOperandSwap(comp->str()); if (op1->enumerator() && op1->enumerator()->value_known) - value = MathLib::toString(op1->enumerator()->value); + value = std::to_string(op1->enumerator()->value); else value = op1->str(); expr = op2; @@ -1048,7 +1048,7 @@ static bool parseComparison(const Token *comp, bool ¬1, std::string &op, std: return false; op = comp->str(); if (op2->enumerator() && op2->enumerator()->value_known) - value = MathLib::toString(op2->enumerator()->value); + value = std::to_string(op2->enumerator()->value); else value = op2->str(); expr = op1; diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 9ab231a36b1..123189bde37 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -3518,7 +3518,7 @@ void CheckOther::funcArgNamesDifferent(const std::string & functionName, nonneg std::list tokens = { declaration,definition }; reportError(tokens, Severity::style, "funcArgNamesDifferent", "$symbol:" + functionName + "\n" - "Function '$symbol' argument " + MathLib::toString(index + 1) + " names different: declaration '" + + "Function '$symbol' argument " + std::to_string(index + 1) + " names different: declaration '" + (declaration ? declaration->str() : std::string("A")) + "' definition '" + (definition ? definition->str() : std::string("B")) + "'.", CWE628, Certainty::inconclusive); } diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index e89eb254d61..6f7d6fa0463 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -203,14 +203,14 @@ void CheckStl::outOfBounds() static std::string indexValueString(const ValueFlow::Value& indexValue, const std::string& containerName = emptyString) { if (indexValue.isIteratorStartValue()) - return "at position " + MathLib::toString(indexValue.intvalue) + " from the beginning"; + return "at position " + std::to_string(indexValue.intvalue) + " from the beginning"; if (indexValue.isIteratorEndValue()) - return "at position " + MathLib::toString(-indexValue.intvalue) + " from the end"; - std::string indexString = MathLib::toString(indexValue.intvalue); + return "at position " + std::to_string(-indexValue.intvalue) + " from the end"; + std::string indexString = std::to_string(indexValue.intvalue); if (indexValue.isSymbolicValue()) { indexString = containerName + ".size()"; if (indexValue.intvalue != 0) - indexString += "+" + MathLib::toString(indexValue.intvalue); + indexString += "+" + std::to_string(indexValue.intvalue); } if (indexValue.bound == ValueFlow::Value::Bound::Lower) return "greater or equal to " + indexString; @@ -242,11 +242,11 @@ void CheckStl::outOfBoundsError(const Token *tok, const std::string &containerNa errmsg = "Out of bounds access in expression '" + expression + "' because '$symbol' is empty."; } else if (indexValue) { if (containerSize->condition) - errmsg = ValueFlow::eitherTheConditionIsRedundant(containerSize->condition) + " or $symbol size can be " + MathLib::toString(containerSize->intvalue) + ". Expression '" + expression + "' cause access out of bounds."; + errmsg = ValueFlow::eitherTheConditionIsRedundant(containerSize->condition) + " or $symbol size can be " + std::to_string(containerSize->intvalue) + ". Expression '" + expression + "' cause access out of bounds."; else if (indexValue->condition) errmsg = ValueFlow::eitherTheConditionIsRedundant(indexValue->condition) + " or '" + index + "' can have the value " + indexValueString(*indexValue) + ". Expression '" + expression + "' cause access out of bounds."; else - errmsg = "Out of bounds access in '" + expression + "', if '$symbol' size is " + MathLib::toString(containerSize->intvalue) + " and '" + index + "' is " + indexValueString(*indexValue); + errmsg = "Out of bounds access in '" + expression + "', if '$symbol' size is " + std::to_string(containerSize->intvalue) + " and '" + index + "' is " + indexValueString(*indexValue); } else { // should not happen return; diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 67681de63b5..f336630bcd1 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -807,7 +807,7 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string const std::list &directives = preprocessor.getDirectives(); for (const Directive &dir : directives) { if (dir.str.compare(0,8,"#define ") == 0 || dir.str.compare(0,9,"#include ") == 0) - code += "#line " + MathLib::toString(dir.linenr) + " \"" + dir.file + "\"\n" + dir.str + '\n'; + code += "#line " + std::to_string(dir.linenr) + " \"" + dir.file + "\"\n" + dir.str + '\n'; } Tokenizer tokenizer2(&mSettings, this); std::istringstream istr2(code); @@ -945,7 +945,7 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string } catch (const simplecpp::Output &o) { // #error etc during preprocessing - configurationError.push_back((mCurrentConfig.empty() ? "\'\'" : mCurrentConfig) + " : [" + o.location.file() + ':' + MathLib::toString(o.location.line) + "] " + o.msg); + configurationError.push_back((mCurrentConfig.empty() ? "\'\'" : mCurrentConfig) + " : [" + o.location.file() + ':' + std::to_string(o.location.line) + "] " + o.msg); --checkCount; // don't count invalid configurations continue; diff --git a/lib/ctu.cpp b/lib/ctu.cpp index d62f91bfb86..5105628c728 100644 --- a/lib/ctu.cpp +++ b/lib/ctu.cpp @@ -59,7 +59,7 @@ int CTU::maxCtuDepth = 2; std::string CTU::getFunctionId(const Tokenizer *tokenizer, const Function *function) { - return tokenizer->list.file(function->tokenDef) + ':' + MathLib::toString(function->tokenDef->linenr()) + ':' + MathLib::toString(function->tokenDef->column()); + return tokenizer->list.file(function->tokenDef) + ':' + std::to_string(function->tokenDef->linenr()) + ':' + std::to_string(function->tokenDef->column()); } CTU::FileInfo::Location::Location(const Tokenizer *tokenizer, const Token *tok) @@ -579,7 +579,7 @@ std::list CTU::FileInfo::getErrorPath(InvalidValueTy } ErrorMessage::FileLocation fileLoc(path[index]->location.fileName, path[index]->location.lineNumber, path[index]->location.column); - fileLoc.setinfo("Calling function " + path[index]->callFunctionName + ", " + MathLib::toString(path[index]->callArgNr) + getOrdinalText(path[index]->callArgNr) + " argument is " + value1); + fileLoc.setinfo("Calling function " + path[index]->callFunctionName + ", " + std::to_string(path[index]->callArgNr) + getOrdinalText(path[index]->callArgNr) + " argument is " + value1); locationList.push_back(std::move(fileLoc)); } diff --git a/lib/errorlogger.cpp b/lib/errorlogger.cpp index b9cd3f5104f..f6454e1d569 100644 --- a/lib/errorlogger.cpp +++ b/lib/errorlogger.cpp @@ -240,8 +240,8 @@ std::string ErrorMessage::serialize() const std::string oss; serializeString(oss, id); serializeString(oss, Severity::toString(severity)); - serializeString(oss, MathLib::toString(cwe.id)); - serializeString(oss, MathLib::toString(hash)); + serializeString(oss, std::to_string(cwe.id)); + serializeString(oss, std::to_string(hash)); serializeString(oss, file0); if (certainty == Certainty::inconclusive) { const std::string text("inconclusive"); @@ -461,7 +461,7 @@ std::string ErrorMessage::toXML() const if (cwe.id) printer.PushAttribute("cwe", cwe.id); if (hash) - printer.PushAttribute("hash", MathLib::toString(hash).c_str()); + printer.PushAttribute("hash", std::to_string(hash).c_str()); if (certainty == Certainty::inconclusive) printer.PushAttribute("inconclusive", "true"); @@ -624,14 +624,14 @@ std::string ErrorMessage::toString(bool verbose, const std::string &templateForm pos1 = result.find("{inconclusive:", pos1); } findAndReplace(result, "{severity}", Severity::toString(severity)); - findAndReplace(result, "{cwe}", MathLib::toString(cwe.id)); + findAndReplace(result, "{cwe}", std::to_string(cwe.id)); findAndReplace(result, "{message}", verbose ? mVerboseMessage : mShortMessage); if (!callStack.empty()) { if (result.find("{callstack}") != std::string::npos) findAndReplace(result, "{callstack}", ErrorLogger::callStackToString(callStack)); findAndReplace(result, "{file}", callStack.back().getfile()); - findAndReplace(result, "{line}", MathLib::toString(callStack.back().line)); - findAndReplace(result, "{column}", MathLib::toString(callStack.back().column)); + findAndReplace(result, "{line}", std::to_string(callStack.back().line)); + findAndReplace(result, "{column}", std::to_string(callStack.back().column)); if (result.find("{code}") != std::string::npos) { const std::string::size_type pos = result.find('\r'); const char *endl; @@ -660,8 +660,8 @@ std::string ErrorMessage::toString(bool verbose, const std::string &templateForm std::string text = templateLocation; findAndReplace(text, "{file}", fileLocation.getfile()); - findAndReplace(text, "{line}", MathLib::toString(fileLocation.line)); - findAndReplace(text, "{column}", MathLib::toString(fileLocation.column)); + findAndReplace(text, "{line}", std::to_string(fileLocation.line)); + findAndReplace(text, "{column}", std::to_string(fileLocation.column)); findAndReplace(text, "{info}", fileLocation.getinfo().empty() ? mShortMessage : fileLocation.getinfo()); if (text.find("{code}") != std::string::npos) { const std::string::size_type pos = text.find('\r'); diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index 7feef1f8c57..5a3b65f17fd 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -1059,7 +1059,7 @@ std::string MathLib::add(const std::string & first, const std::string & second) return (value(first) + value(second)).str(); #else if (MathLib::isInt(first) && MathLib::isInt(second)) { - return toString(toLongNumber(first) + toLongNumber(second)) + intsuffix(first, second); + return std::to_string(toLongNumber(first) + toLongNumber(second)) + intsuffix(first, second); } double d1 = toDoubleNumber(first); @@ -1081,7 +1081,7 @@ std::string MathLib::subtract(const std::string &first, const std::string &secon return (value(first) - value(second)).str(); #else if (MathLib::isInt(first) && MathLib::isInt(second)) { - return toString(toLongNumber(first) - toLongNumber(second)) + intsuffix(first, second); + return std::to_string(toLongNumber(first) - toLongNumber(second)) + intsuffix(first, second); } if (first == second) @@ -1112,7 +1112,7 @@ std::string MathLib::divide(const std::string &first, const std::string &second) throw InternalError(nullptr, "Internal Error: Division by zero"); if (a == std::numeric_limits::min() && std::abs(b)<=1) throw InternalError(nullptr, "Internal Error: Division overflow"); - return toString(toLongNumber(first) / b) + intsuffix(first, second); + return std::to_string(toLongNumber(first) / b) + intsuffix(first, second); } if (isNullValue(second)) { if (isNullValue(first)) @@ -1129,7 +1129,7 @@ std::string MathLib::multiply(const std::string &first, const std::string &secon return (value(first) * value(second)).str(); #else if (MathLib::isInt(first) && MathLib::isInt(second)) { - return toString(toLongNumber(first) * toLongNumber(second)) + intsuffix(first, second); + return std::to_string(toLongNumber(first) * toLongNumber(second)) + intsuffix(first, second); } return toString(toDoubleNumber(first) * toDoubleNumber(second)); #endif @@ -1144,7 +1144,7 @@ std::string MathLib::mod(const std::string &first, const std::string &second) const bigint b = toLongNumber(second); if (b == 0) throw InternalError(nullptr, "Internal Error: Division by zero"); - return toString(toLongNumber(first) % b) + intsuffix(first, second); + return std::to_string(toLongNumber(first) % b) + intsuffix(first, second); } return toString(std::fmod(toDoubleNumber(first),toDoubleNumber(second))); #endif @@ -1169,13 +1169,13 @@ std::string MathLib::calculate(const std::string &first, const std::string &seco return MathLib::mod(first, second); case '&': - return MathLib::toString(MathLib::toLongNumber(first) & MathLib::toLongNumber(second)) + intsuffix(first,second); + return std::to_string(MathLib::toLongNumber(first) & MathLib::toLongNumber(second)) + intsuffix(first,second); case '|': - return MathLib::toString(MathLib::toLongNumber(first) | MathLib::toLongNumber(second)) + intsuffix(first,second); + return std::to_string(MathLib::toLongNumber(first) | MathLib::toLongNumber(second)) + intsuffix(first,second); case '^': - return MathLib::toString(MathLib::toLongNumber(first) ^ MathLib::toLongNumber(second)) + intsuffix(first,second); + return std::to_string(MathLib::toLongNumber(first) ^ MathLib::toLongNumber(second)) + intsuffix(first,second); default: throw InternalError(nullptr, std::string("Unexpected action '") + action + "' in MathLib::calculate(). Please report this to Cppcheck developers."); diff --git a/lib/mathlib.h b/lib/mathlib.h index 9bab55a8d82..a7e4b3c8806 100644 --- a/lib/mathlib.h +++ b/lib/mathlib.h @@ -74,9 +74,7 @@ class CPPCHECKLIB MathLib { /** @brief for conversion of numeric literals - for atoi-like conversions please use strToInt() */ static biguint toULongNumber(const std::string & str); - template static std::string toString(T value) { - return std::to_string(value); - } + template static std::string toString(T value) = delete; /** @brief for conversion of numeric literals */ static double toDoubleNumber(const std::string & str); @@ -147,7 +145,7 @@ MathLib::value operator^(const MathLib::value &v1, const MathLib::value &v2); MathLib::value operator<<(const MathLib::value &v1, const MathLib::value &v2); MathLib::value operator>>(const MathLib::value &v1, const MathLib::value &v2); -template<> CPPCHECKLIB std::string MathLib::toString(double value); // Declare specialization to avoid linker problems +template<> CPPCHECKLIB std::string MathLib::toString(double value); /// @} //--------------------------------------------------------------------------- diff --git a/lib/suppressions.cpp b/lib/suppressions.cpp index 8b0095edc6b..ca5676e04f1 100644 --- a/lib/suppressions.cpp +++ b/lib/suppressions.cpp @@ -356,11 +356,11 @@ std::string Suppressions::Suppression::getText() const if (!fileName.empty()) ret += " fileName=" + fileName; if (lineNumber != NO_LINE) - ret += " lineNumber=" + MathLib::toString(lineNumber); + ret += " lineNumber=" + std::to_string(lineNumber); if (!symbolName.empty()) ret += " symbolName=" + symbolName; if (hash > 0) - ret += " hash=" + MathLib::toString(hash); + ret += " hash=" + std::to_string(hash); if (ret.compare(0,1," ")==0) return ret.substr(1); return ret; diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 37c9a5b003b..17700105b27 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -7637,7 +7637,7 @@ void ValueType::setDebugPath(const Token* tok, SourceLocation ctx, SourceLocatio std::string file = ctx.file_name(); if (file.empty()) return; - std::string s = Path::stripDirectoryPart(file) + ":" + MathLib::toString(ctx.line()) + ": " + ctx.function_name() + + std::string s = Path::stripDirectoryPart(file) + ":" + std::to_string(ctx.line()) + ": " + ctx.function_name() + " => " + local.function_name(); debugPath.emplace_back(tok, std::move(s)); } diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index dbd80226941..e79046cc644 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -2483,17 +2483,17 @@ void TemplateSimplifier::simplifyTemplateArgs(Token *start, const Token *end, st } else if (Token::Match(tok->next(), "( %type% * )")) { - tok->str(MathLib::toString(mTokenizer.sizeOfType(tok->tokAt(3)))); + tok->str(std::to_string(mTokenizer.sizeOfType(tok->tokAt(3)))); tok->deleteNext(4); again = true; } else if (Token::simpleMatch(tok->next(), "( * )")) { - tok->str(MathLib::toString(mTokenizer.sizeOfType(tok->tokAt(2)))); + tok->str(std::to_string(mTokenizer.sizeOfType(tok->tokAt(2)))); tok->deleteNext(3); again = true; } else if (Token::Match(tok->next(), "( %type% )")) { const unsigned int size = mTokenizer.sizeOfType(tok->tokAt(2)); if (size > 0) { - tok->str(MathLib::toString(size)); + tok->str(std::to_string(size)); tok->deleteNext(3); again = true; } @@ -2678,7 +2678,7 @@ bool TemplateSimplifier::simplifyCalculations(Token* frontToken, const Token *ba if (validTokenEnd(bounded, tok, backToken, 3) && Token::Match(tok->previous(), "(|&&|%oror% %char% %comp% %num% &&|%oror%|)")) { - tok->str(MathLib::toString(MathLib::toLongNumber(tok->str()))); + tok->str(std::to_string(MathLib::toLongNumber(tok->str()))); } if (validTokenEnd(bounded, tok, backToken, 5) && @@ -3085,7 +3085,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations( Severity::information, "templateRecursion", "TemplateSimplifier: max template recursion (" - + MathLib::toString(mSettings.maxTemplateRecursion) + + std::to_string(mSettings.maxTemplateRecursion) + ") reached for template '"+typeForNewName+"'. You might want to limit Cppcheck recursion.", Certainty::normal); mErrorLogger->reportErr(errmsg); diff --git a/lib/token.cpp b/lib/token.cpp index a1d2cfd6f1c..3f5a539c963 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -1571,7 +1571,7 @@ static void astStringXml(const Token *tok, nonneg int indent, std::ostream &out) out << strindent << "str() << '\"'; if (tok->varId()) - out << " varId=\"" << MathLib::toString(tok->varId()) << '\"'; + out << " varId=\"" << tok->varId() << '\"'; if (tok->variable()) out << " variable=\"" << tok->variable() << '\"'; if (tok->function()) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index ec63858ff22..0c9ac365315 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -448,7 +448,7 @@ static Token *splitDefinitionFromTypedef(Token *tok, nonneg int *unnamedCount) if (Token::Match(tok1->next(), "%type%")) name = tok1->next()->str(); else // create a unique name - name = "Unnamed" + MathLib::toString((*unnamedCount)++); + name = "Unnamed" + std::to_string((*unnamedCount)++); tok->next()->insertToken(name); } else return nullptr; @@ -2920,7 +2920,7 @@ bool Tokenizer::simplifyUsing() if (structEnd->strAt(2) == ";") newName = name; else - newName = "Unnamed" + MathLib::toString(mUnnamedCount++); + newName = "Unnamed" + std::to_string(mUnnamedCount++); TokenList::copyTokens(structEnd->next(), tok, start); structEnd->tokAt(5)->insertToken(newName, emptyString); start->insertToken(newName, emptyString); @@ -3737,7 +3737,7 @@ void Tokenizer::arraySize() Token* endStmt{}; if (const Token* strTok = getStrTok(tok, addlength, &endStmt)) { const int sz = Token::getStrArraySize(strTok); - tok->next()->insertToken(MathLib::toString(sz)); + tok->next()->insertToken(std::to_string(sz)); tok = endStmt; } @@ -3767,7 +3767,7 @@ void Tokenizer::arraySize() } if (sz != 0) - tok->insertToken(MathLib::toString(sz)); + tok->insertToken(std::to_string(sz)); tok = end->next() ? end->next() : end; } @@ -3899,7 +3899,7 @@ void Tokenizer::simplifyCaseRange() tok->insertToken("case"); for (MathLib::bigint i = end-1; i > start; i--) { tok->insertToken(":"); - tok->insertToken(MathLib::toString(i)); + tok->insertToken(std::to_string(i)); tok->insertToken("case"); } } @@ -5785,7 +5785,7 @@ void Tokenizer::printDebugOutput(int simplification) const reportError(var->typeStartToken(), Severity::debug, "debug", - "Variable::typeStartToken() of variable '" + var->name() + "' is not located before Variable::typeEndToken(). The location of the typeStartToken() is '" + var->typeStartToken()->str() + "' at line " + MathLib::toString(var->typeStartToken()->linenr())); + "Variable::typeStartToken() of variable '" + var->name() + "' is not located before Variable::typeEndToken(). The location of the typeStartToken() is '" + var->typeStartToken()->str() + "' at line " + std::to_string(var->typeStartToken()->linenr())); } } } @@ -5861,9 +5861,9 @@ void Tokenizer::dump(std::ostream &out) const if (tok->link()) out << " link=\"" << tok->link() << '\"'; if (tok->varId() > 0) - out << " varId=\"" << MathLib::toString(tok->varId()) << '\"'; + out << " varId=\"" << tok->varId() << '\"'; if (tok->exprId() > 0) - out << " exprId=\"" << MathLib::toString(tok->exprId()) << '\"'; + out << " exprId=\"" << tok->exprId() << '\"'; if (tok->variable()) out << " variable=\"" << tok->variable() << '\"'; if (tok->function()) @@ -8592,14 +8592,14 @@ void Tokenizer::simplifyStructDecl() // check for anonymous struct/union if (Token::Match(tok, "struct|union {")) { if (Token::Match(tok->next()->link(), "} const| *|&| const| %type% ,|;|[|(|{|=")) { - tok->insertToken("Anonymous" + MathLib::toString(count++)); + tok->insertToken("Anonymous" + std::to_string(count++)); } } // check for derived anonymous class/struct else if (cpp && Token::Match(tok, "class|struct :")) { const Token *tok1 = Token::findsimplematch(tok, "{"); if (tok1 && Token::Match(tok1->link(), "} const| *|&| const| %type% ,|;|[|(|{")) { - tok->insertToken("Anonymous" + MathLib::toString(count++)); + tok->insertToken("Anonymous" + std::to_string(count++)); } } // check for anonymous enum @@ -8612,7 +8612,7 @@ void Tokenizer::simplifyStructDecl() start->next()->link()->deleteThis(); start->next()->deleteThis(); } - tok->insertToken("Anonymous" + MathLib::toString(count++)); + tok->insertToken("Anonymous" + std::to_string(count++)); } } @@ -9850,7 +9850,7 @@ void Tokenizer::simplifyOperatorName() tok->insertToken("("); str->insertToken(")"); Token::createMutualLinks(tok->next(), str->next()); - str->insertToken(MathLib::toString(Token::getStrLength(str))); + str->insertToken(std::to_string(Token::getStrLength(str))); str->insertToken(","); } } diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 31077d831f5..c6e374f8ae6 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -385,9 +385,9 @@ std::size_t TokenList::calculateHash() const { std::string hashData; for (const Token* tok = front(); tok; tok = tok->next()) { - hashData += MathLib::toString(tok->flags()); - hashData += MathLib::toString(tok->varId()); - hashData += MathLib::toString(tok->tokType()); + hashData += std::to_string(tok->flags()); + hashData += std::to_string(tok->varId()); + hashData += std::to_string(tok->tokType()); hashData += tok->str(); hashData += tok->originalName(); } diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 1a280f9d845..8ed4f29cc6c 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -132,7 +132,7 @@ static void bailoutInternal(const std::string& type, TokenList &tokenlist, Error function = "(valueFlow)"; std::list callstack(1, ErrorMessage::FileLocation(tok, &tokenlist)); ErrorMessage errmsg(callstack, tokenlist.getSourceFilePath(), Severity::debug, - Path::stripDirectoryPart(file) + ":" + MathLib::toString(line) + ":" + function + " bailout: " + what, type, Certainty::normal); + Path::stripDirectoryPart(file) + ":" + std::to_string(line) + ":" + function + " bailout: " + what, type, Certainty::normal); errorLogger->reportErr(errmsg); } @@ -169,7 +169,7 @@ static void setSourceLocation(ValueFlow::Value& v, std::string file = ctx.file_name(); if (file.empty()) return; - std::string s = Path::stripDirectoryPart(file) + ":" + MathLib::toString(ctx.line()) + ": " + ctx.function_name() + + std::string s = Path::stripDirectoryPart(file) + ":" + std::to_string(ctx.line()) + ": " + ctx.function_name() + " => " + local.function_name() + ": " + debugString(v); v.debugPath.emplace_back(tok, std::move(s)); } @@ -7613,7 +7613,7 @@ static void valueFlowSubFunction(TokenList& tokenlist, SymbolDatabase& symboldat // Error path.. for (ValueFlow::Value &v : argvalues) { - const std::string nr = MathLib::toString(argnr + 1) + getOrdinalText(argnr + 1); + const std::string nr = std::to_string(argnr + 1) + getOrdinalText(argnr + 1); v.errorPath.emplace_back(argtok, "Calling function '" + @@ -9038,7 +9038,7 @@ static void valueFlowDynamicBufferSize(const TokenList& tokenlist, const SymbolD continue; ValueFlow::Value value(sizeValue); - value.errorPath.emplace_back(tok->tokAt(2), "Assign " + tok->strAt(1) + ", buffer with size " + MathLib::toString(sizeValue)); + value.errorPath.emplace_back(tok->tokAt(2), "Assign " + tok->strAt(1) + ", buffer with size " + std::to_string(sizeValue)); value.valueType = ValueFlow::Value::ValueType::BUFFER_SIZE; value.setKnown(); valueFlowForward(const_cast(rhs), functionScope->bodyEnd, tok->next(), std::move(value), tokenlist, settings); @@ -9189,12 +9189,12 @@ static void valueFlowSafeFunctions(TokenList& tokenlist, const SymbolDatabase& s std::list argValues; if (isLow) { argValues.emplace_back(low); - argValues.back().errorPath.emplace_back(arg.nameToken(), std::string(safeLow ? "Safe checks: " : "") + "Assuming argument has value " + MathLib::toString(low)); + argValues.back().errorPath.emplace_back(arg.nameToken(), std::string(safeLow ? "Safe checks: " : "") + "Assuming argument has value " + std::to_string(low)); argValues.back().safe = safeLow; } if (isHigh) { argValues.emplace_back(high); - argValues.back().errorPath.emplace_back(arg.nameToken(), std::string(safeHigh ? "Safe checks: " : "") + "Assuming argument has value " + MathLib::toString(high)); + argValues.back().errorPath.emplace_back(arg.nameToken(), std::string(safeHigh ? "Safe checks: " : "") + "Assuming argument has value " + std::to_string(high)); argValues.back().safe = safeHigh; } diff --git a/lib/vfvalue.cpp b/lib/vfvalue.cpp index 6a1ba6f3b9d..c99a76dd305 100644 --- a/lib/vfvalue.cpp +++ b/lib/vfvalue.cpp @@ -96,7 +96,7 @@ namespace ValueFlow { std::string Value::infoString() const { switch (valueType) { case ValueType::INT: - return MathLib::toString(intvalue); + return std::to_string(intvalue); case ValueType::TOK: return tokvalue->str(); case ValueType::FLOAT: @@ -107,19 +107,19 @@ namespace ValueFlow { return ""; case ValueType::BUFFER_SIZE: case ValueType::CONTAINER_SIZE: - return "size=" + MathLib::toString(intvalue); + return "size=" + std::to_string(intvalue); case ValueType::ITERATOR_START: - return "start=" + MathLib::toString(intvalue); + return "start=" + std::to_string(intvalue); case ValueType::ITERATOR_END: - return "end=" + MathLib::toString(intvalue); + return "end=" + std::to_string(intvalue); case ValueType::LIFETIME: return "lifetime=" + tokvalue->str(); case ValueType::SYMBOLIC: std::string result = "symbolic=" + tokvalue->expressionString(); if (intvalue > 0) - result += "+" + MathLib::toString(intvalue); + result += "+" + std::to_string(intvalue); else if (intvalue < 0) - result += "-" + MathLib::toString(-intvalue); + result += "-" + std::to_string(-intvalue); return result; } throw InternalError(nullptr, "Invalid ValueFlow Value type"); diff --git a/test/testgarbage.cpp b/test/testgarbage.cpp index 83219bacf76..d2ad9d0a44e 100644 --- a/test/testgarbage.cpp +++ b/test/testgarbage.cpp @@ -311,7 +311,7 @@ class TestGarbage : public TestFixture { } catch (InternalError& e) { if (e.id != "syntaxError") return ""; - return "[test.cpp:" + MathLib::toString(e.token->linenr()) + "] " + e.errorMessage; + return "[test.cpp:" + std::to_string(e.token->linenr()) + "] " + e.errorMessage; } return ""; } diff --git a/test/testmathlib.cpp b/test/testmathlib.cpp index 9a31110f1d2..7b9e5acd590 100644 --- a/test/testmathlib.cpp +++ b/test/testmathlib.cpp @@ -1463,23 +1463,12 @@ class TestMathLib : public TestFixture { ASSERT_EQUALS("0.0", MathLib::toString(0.0)); ASSERT_EQUALS("0.0", MathLib::toString(+0.0)); ASSERT_EQUALS("0.0", MathLib::toString(-0.0)); - // float (trailing f or F) - ASSERT_EQUALS("0.000000", MathLib::toString(0.0f)); - ASSERT_EQUALS("0.000000", MathLib::toString(+0.0f)); - ASSERT_EQUALS("-0.000000", MathLib::toString(-0.0f)); - ASSERT_EQUALS("0.000000", MathLib::toString(0.0F)); - ASSERT_EQUALS("0.000000", MathLib::toString(+0.0F)); - ASSERT_EQUALS("-0.000000", MathLib::toString(-0.0F)); - // double (tailing l or L) - ASSERT_EQUALS("0.000000", MathLib::toString(0.0l)); - ASSERT_EQUALS("0.000000", MathLib::toString(+0.0l)); - ASSERT_EQUALS("-0.000000", MathLib::toString(-0.0l)); - ASSERT_EQUALS("0.000000", MathLib::toString(0.0L)); - ASSERT_EQUALS("0.000000", MathLib::toString(+0.0L)); - ASSERT_EQUALS("-0.000000", MathLib::toString(-0.0L)); ASSERT_EQUALS("1e-08", MathLib::toString(0.00000001)); ASSERT_EQUALS("-1e-08", MathLib::toString(-0.00000001)); + + ASSERT_EQUALS("2.22507385851e-308", MathLib::toString(std::numeric_limits::min())); + ASSERT_EQUALS("1.79769313486e+308", MathLib::toString(std::numeric_limits::max())); } void CPP14DigitSeparators() const { // Ticket #7137, #7565 diff --git a/test/testvarid.cpp b/test/testvarid.cpp index 341c24c2d9c..c3d2fcd76bf 100644 --- a/test/testvarid.cpp +++ b/test/testvarid.cpp @@ -2122,7 +2122,7 @@ class TestVarID : public TestFixture { } static std::string getLine(const std::string &code, int lineNumber) { - std::string nr = MathLib::toString(lineNumber); + std::string nr = std::to_string(lineNumber); const std::string::size_type pos1 = code.find('\n' + nr + ": "); if (pos1 == std::string::npos) return ""; From 5dbcea3f1dc09503c593628aad7b3aad6198db20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Thu, 17 Aug 2023 17:01:08 +0200 Subject: [PATCH 19/30] enabled and mitigated `readability-container-size-empty` clang-tidy warnings (#5340) --- .clang-tidy | 1 - clang-tidy.md | 1 - gui/mainwindow.cpp | 2 +- gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp | 2 +- lib/checkother.cpp | 4 ++-- lib/templatesimplifier.cpp | 2 +- test/testsymboldatabase.cpp | 1 + test/testvalueflow.cpp | 2 +- 8 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 540d5a7e878..96c8908f0c0 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -56,7 +56,6 @@ Checks: > -readability-braces-around-statements, -readability-const-return-type, -readability-container-data-pointer, - -readability-container-size-empty, -readability-convert-member-functions-to-static, -readability-function-cognitive-complexity, -readability-function-size, diff --git a/clang-tidy.md b/clang-tidy.md index a2e2dd5db5e..b85031ac25c 100644 --- a/clang-tidy.md +++ b/clang-tidy.md @@ -128,7 +128,6 @@ Also reports a false positive about templates which deduce the array length: htt We run this separately via `clang-include-cleaner` in the `iwyu.yml` workflow as the findings of the include checkers still need to be reviewed manually before applying them. -`readability-container-size-empty`
`bugprone-branch-clone`
`readability-const-return-type`
`modernize-return-braced-init-list`
diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 2840c48330d..fd5dc6dfff0 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -697,7 +697,7 @@ void MainWindow::analyzeFiles() QStringList selected = selectFilesToAnalyze(QFileDialog::ExistingFiles); - const QString file0 = (selected.size() ? selected[0].toLower() : QString()); + const QString file0 = (!selected.empty() ? selected[0].toLower() : QString()); if (file0.endsWith(".sln") || file0.endsWith(".vcxproj") || file0.endsWith(compile_commands_json) diff --git a/gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp b/gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp index aadb090d1e7..015e8a60dec 100644 --- a/gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp +++ b/gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp @@ -620,7 +620,7 @@ void TestCppcheckLibraryData::validateAllCfg() { const QDir dir(QString(SRCDIR) + "/../../../cfg/"); const QStringList files = dir.entryList(QStringList() << "*.cfg",QDir::Files); - QVERIFY(files.size() != 0); + QVERIFY(!files.empty()); bool error = false; for (const QString& f : files) { loadCfgFile(dir.absolutePath() + "/" + f, fileLibraryData, result); diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 123189bde37..6b94c3484b0 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -3529,8 +3529,8 @@ void CheckOther::funcArgOrderDifferent(const std::string & functionName, const std::vector & definitions) { std::list tokens = { - declarations.size() ? declarations[0] ? declarations[0] : declaration : nullptr, - definitions.size() ? definitions[0] ? definitions[0] : definition : nullptr + !declarations.empty() ? declarations[0] ? declarations[0] : declaration : nullptr, + !definitions.empty() ? definitions[0] ? definitions[0] : definition : nullptr }; std::string msg = "$symbol:" + functionName + "\nFunction '$symbol' argument order different: declaration '"; for (int i = 0; i < declarations.size(); ++i) { diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index e79046cc644..f906fbb91d9 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -3356,7 +3356,7 @@ void TemplateSimplifier::replaceTemplateUsage( std::set* pointers = nameTok->templateSimplifierPointers(); // check if instantiation matches token instantiation from pointer - if (pointers && pointers->size()) { + if (pointers && !pointers->empty()) { // check full name if (instantiation.fullName() != (*pointers->begin())->fullName()) { // FIXME: fallback to just matching name diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 13e719e46c6..f97f3373fa5 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -1921,6 +1921,7 @@ class TestSymbolDatabase : public TestFixture { ASSERT_EQUALS(10, db->variableList().size() - 1); ASSERT_EQUALS(true, db->getVariableFromVarId(1) && db->getVariableFromVarId(1)->dimensions().size() == 1); ASSERT_EQUALS(true, db->getVariableFromVarId(2) != nullptr); + // NOLINTNEXTLINE(readability-container-size-empty) ASSERT_EQUALS(true, db->getVariableFromVarId(3) && db->getVariableFromVarId(3)->dimensions().size() == 0); ASSERT_EQUALS(true, db->getVariableFromVarId(4) != nullptr); ASSERT_EQUALS(true, db->getVariableFromVarId(5) != nullptr); diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index d9faba92820..50a58464abf 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -6616,7 +6616,7 @@ class TestValueFlow : public TestFixture { " if (a.empty() && b.empty()) {}\n" " else if (a.empty() == false && b.empty() == false) {}\n" "}\n"; - ASSERT("" != isImpossibleContainerSizeValue(tokenValues(code, "a . empty ( ) == false"), 0)); + ASSERT(!isImpossibleContainerSizeValue(tokenValues(code, "a . empty ( ) == false"), 0).empty()); code = "bool g(std::vector& v) {\n" " v.push_back(1);\n" From 827e87afe793a0f04c59456335f808d282eae59b Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 18 Aug 2023 10:32:52 +0200 Subject: [PATCH 20/30] Fix #11579 FN knownConditionTrueFalse with non-bool as bool parameter / #9450 string literal to bool conversion in function call (#5338) --- lib/astutils.cpp | 13 +++++++++++++ lib/astutils.h | 7 ++++++- lib/checkcondition.cpp | 11 ++++++++--- lib/checkstring.cpp | 4 +++- lib/forwardanalyzer.cpp | 2 +- lib/token.cpp | 9 +++++++++ lib/token.h | 1 + lib/tokenlist.cpp | 2 +- test/testcondition.cpp | 15 +++++++++++++++ test/teststring.cpp | 7 +++++++ 10 files changed, 64 insertions(+), 7 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 397ad5337f6..bc85cfab931 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -1464,6 +1464,19 @@ static bool astIsBoolLike(const Token* tok) return astIsBool(tok) || isUsedAsBool(tok); } +bool isBooleanFuncArg(const Token* tok) { + if (tok->variable() && tok->variable()->valueType() && tok->variable()->valueType()->type == ValueType::BOOL) // skip trivial case: bool passed as bool + return false; + int argn{}; + const Token* ftok = getTokenArgumentFunction(tok, argn); + if (!ftok) + return false; + std::vector argvars = getArgumentVars(ftok, argn); + if (argvars.size() != 1) + return false; + return !argvars[0]->isReference() && argvars[0]->valueType() && argvars[0]->valueType()->type == ValueType::BOOL; +} + bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2, const Library& library, bool pure, bool followVar, ErrorPath* errors) { if (tok1 == nullptr && tok2 == nullptr) diff --git a/lib/astutils.h b/lib/astutils.h index 4ffd0aa792a..0ef08ece023 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -252,10 +252,15 @@ bool isStructuredBindingVariable(const Variable* var); const Token* isInLoopCondition(const Token* tok); /** - * Is token used a boolean, that is to say cast to a bool, or used as a condition in a if/while/for + * Is token used as boolean, that is to say cast to a bool, or used as a condition in a if/while/for */ CPPCHECKLIB bool isUsedAsBool(const Token * const tok); +/** + * Is token passed to a function taking a bool argument + */ +CPPCHECKLIB bool isBooleanFuncArg(const Token* tok); + /** * Are two conditions opposite * @param isNot do you want to know if cond1 is !cond2 or if cond1 and cond2 are non-overlapping. true: cond1==!cond2 false: cond1==true => cond2==false diff --git a/lib/checkcondition.cpp b/lib/checkcondition.cpp index 2d018f1fb31..8219d04b1ec 100644 --- a/lib/checkcondition.cpp +++ b/lib/checkcondition.cpp @@ -1466,7 +1466,7 @@ void CheckCondition::alwaysTrueFalse() for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) { if (Token::simpleMatch(tok, "<") && tok->link()) // don't write false positives when templates are used continue; - if (!tok->hasKnownIntValue()) + if (!tok->hasKnownBoolValue()) continue; if (Token::Match(tok->previous(), "%name% (") && tok->previous()->function()) { const Function* f = tok->previous()->function(); @@ -1490,6 +1490,8 @@ void CheckCondition::alwaysTrueFalse() else if (parent->str() == ";" && parent->astParent() && parent->astParent()->astParent() && Token::simpleMatch(parent->astParent()->astParent()->previous(), "for (")) condition = parent->astParent()->astParent()->previous(); + else if (isBooleanFuncArg(tok)) + condition = tok; else continue; } @@ -1580,14 +1582,17 @@ void CheckCondition::alwaysTrueFalse() if (hasSizeof) continue; - alwaysTrueFalseError(tok, condition, &tok->values().front()); + auto it = std::find_if(tok->values().begin(), tok->values().end(), [](const ValueFlow::Value& v) { + return v.isIntValue(); + }); + alwaysTrueFalseError(tok, condition, &*it); } } } void CheckCondition::alwaysTrueFalseError(const Token* tok, const Token* condition, const ValueFlow::Value* value) { - const bool alwaysTrue = value && (value->intvalue != 0); + const bool alwaysTrue = value && (value->intvalue != 0 || value->isImpossible()); const std::string expr = tok ? tok->expressionString() : std::string("x"); const std::string conditionStr = (Token::simpleMatch(condition, "return") ? "Return value" : "Condition"); const std::string errmsg = conditionStr + " '" + expr + "' is always " + (alwaysTrue ? "true" : "false"); diff --git a/lib/checkstring.cpp b/lib/checkstring.cpp index cd6617abbd0..afdad191c19 100644 --- a/lib/checkstring.cpp +++ b/lib/checkstring.cpp @@ -292,8 +292,10 @@ void CheckString::checkIncorrectStringCompare() incorrectStringBooleanError(tok->next(), tok->strAt(1)); } else if (Token::Match(tok, "if|while ( %str%|%char% )") && !tok->tokAt(2)->getValue(0)) { incorrectStringBooleanError(tok->tokAt(2), tok->strAt(2)); - } else if (tok->str() == "?" && Token::Match(tok->astOperand1(), "%str%|%char%")) + } else if (tok->str() == "?" && Token::Match(tok->astOperand1(), "%str%|%char%")) { incorrectStringBooleanError(tok->astOperand1(), tok->astOperand1()->str()); + } else if (Token::Match(tok, "%str%") && isBooleanFuncArg(tok)) + incorrectStringBooleanError(tok, tok->str()); } } } diff --git a/lib/forwardanalyzer.cpp b/lib/forwardanalyzer.cpp index fea0526eb5d..09abde664c1 100644 --- a/lib/forwardanalyzer.cpp +++ b/lib/forwardanalyzer.cpp @@ -488,7 +488,7 @@ struct ForwardTraversal { if (allAnalysis.isIncremental()) return Break(Analyzer::Terminate::Bail); } else if (allAnalysis.isModified()) { - std::vector ftv = tryForkScope(endBlock, allAnalysis.isModified()); + std::vector ftv = tryForkScope(endBlock, /*isModified*/ true); bool forkContinue = true; for (ForwardTraversal& ft : ftv) { if (condTok) diff --git a/lib/token.cpp b/lib/token.cpp index 3f5a539c963..618979613d1 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -2371,6 +2371,15 @@ bool Token::hasKnownIntValue() const }); } +bool Token::hasKnownBoolValue() const +{ + if (!mImpl->mValues) + return false; + return std::any_of(mImpl->mValues->begin(), mImpl->mValues->end(), [](const ValueFlow::Value& value) { + return value.isIntValue() && (value.isKnown() || (value.intvalue == 0 && value.isImpossible())); + }); +} + bool Token::hasKnownValue() const { return mImpl->mValues && std::any_of(mImpl->mValues->begin(), mImpl->mValues->end(), std::mem_fn(&ValueFlow::Value::isKnown)); diff --git a/lib/token.h b/lib/token.h index 4163ab754c6..e0ca0ed9d5e 100644 --- a/lib/token.h +++ b/lib/token.h @@ -1212,6 +1212,7 @@ class CPPCHECKLIB Token { } bool hasKnownIntValue() const; + bool hasKnownBoolValue() const; bool hasKnownValue() const; bool hasKnownValue(ValueFlow::Value::ValueType t) const; bool hasKnownSymbolicValue(const Token* tok) const; diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index c6e374f8ae6..34dbc2e0ec5 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -912,7 +912,7 @@ static void compilePrecedence2(Token *&tok, AST_state& state) } compileBinOp(tok, state, compileScope); } else if (tok->str() == "[") { - if (state.cpp && isPrefixUnary(tok, state.cpp) && Token::Match(tok->link(), "] (|{|<")) { // Lambda + if (state.cpp && isPrefixUnary(tok, /*cpp*/ true) && Token::Match(tok->link(), "] (|{|<")) { // Lambda // What we do here: // - Nest the round bracket under the square bracket. // - Nest what follows the lambda (if anything) with the lambda opening [ diff --git a/test/testcondition.cpp b/test/testcondition.cpp index 5cca85c05a8..98fef828051 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -4514,6 +4514,21 @@ class TestCondition : public TestFixture { " return a;\n" "}\n"); ASSERT_EQUALS("[test.cpp:3]: (style) Condition 'a==\"x\"' is always true\n", errout.str()); + + check("void g(bool);\n" + "void f() {\n" + " int i = 5;\n" + " int* p = &i;\n" + " g(i == 7);\n" + " g(p == nullptr);\n" + " g(p);\n" + " g(&i);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5]: (style) Condition 'i==7' is always false\n" + "[test.cpp:6]: (style) Condition 'p==nullptr' is always false\n" + "[test.cpp:7]: (style) Condition 'p' is always true\n" + "[test.cpp:8]: (style) Condition '&i' is always true\n", + errout.str()); } void alwaysTrueSymbolic() diff --git a/test/teststring.cpp b/test/teststring.cpp index 24a4f1c3a54..ca734d352fd 100644 --- a/test/teststring.cpp +++ b/test/teststring.cpp @@ -743,6 +743,13 @@ class TestString : public TestFixture { "}"); ASSERT_EQUALS("[test.cpp:2]: (warning) Conversion of char literal '\\0' to bool always evaluates to false.\n" "[test.cpp:3]: (warning) Conversion of char literal L'\\0' to bool always evaluates to false.\n", errout.str()); + + check("void f(bool b);\n" // #9450 + "void f(std::string s);\n" + "void g() {\n" + " f(\"abc\");\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (warning) Conversion of string literal \"abc\" to bool always evaluates to true.\n", errout.str()); } void deadStrcmp() { From 7f22ef4e14183f768d3a6c74c980990db1f635a1 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 18 Aug 2023 10:33:26 +0200 Subject: [PATCH 21/30] Set ValueType for auto with ternary (#5304) --- addons/test/misra/misra-test.c | 10 +++++----- lib/symboldatabase.cpp | 5 +++++ test/testsymboldatabase.cpp | 22 +++++++++++++++++++--- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/addons/test/misra/misra-test.c b/addons/test/misra/misra-test.c index 2fd30c7e707..d4e7f39ad6c 100644 --- a/addons/test/misra/misra-test.c +++ b/addons/test/misra/misra-test.c @@ -645,11 +645,11 @@ static void misra_10_1_ternary(void) a = ui16 << ui16; // 10.6 a = ui16 << (get_bool(42) ? ui16 : ui16); - a = ui16 << (get_bool(42) ? ui16 : (get_bool(34) ? ui16 : ui16)); // 10.4 - a = ui16 << (get_bool(42) ? (get_bool(34) ? ui16 : ui16) : ui16); // 10.4 - a = ui16 << (get_bool(42) ? i16 : (get_bool(34) ? ui16 : ui16)); // 10.1 + a = ui16 << (get_bool(42) ? ui16 : (get_bool(34) ? ui16 : ui16)); + a = ui16 << (get_bool(42) ? (get_bool(34) ? ui16 : ui16) : ui16); + a = ui16 << (get_bool(42) ? i16 : (get_bool(34) ? ui16 : ui16)); // 10.1 10.4 a = ui16 << (get_bool(42) ? (get_bool(34) ? ui16 : i16) : ui16); // 10.1 10.4 - a = ui16 << (get_bool(42) ? (get_bool(34) ? ui16 : ui16) : i16); // 10.1 + a = ui16 << (get_bool(42) ? (get_bool(34) ? ui16 : ui16) : i16); // 10.1 10.4 a = ui16 << (get_bool(42) ? (get_bool(34) ? ui16 : ui8) : ui8); // 10.4 a = ui16 << (get_bool(42) ? (get_bool(34) ? i16 : ui8) : ui8); // 10.1 10.4 a = (get_bool(42) ? (get_bool(34) ? ui16 : ui8) : ui8) << ui16; // 10.4 @@ -1171,7 +1171,7 @@ static void misra_14_2_fn1(bool b) { g += 2; i2 ^= 2; // 14.2 if (i2 == 2) { - g += g_arr[i2]; + g += g_arr[i2]; // cppcheck-suppress legacyUninitvar } misra_14_2_init_value(&i2); // TODO: Fix false negative in function call } diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 17700105b27..bfc04ae73be 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -6552,6 +6552,11 @@ void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, Source setValueType(parent, *vt1); return; } + + if (vt1->isTypeEqual(vt2)) { + setValueType(parent, *vt1); + return; + } } if (vt1->pointer != 0U) { diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index f97f3373fa5..e558e4d3a36 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -510,6 +510,7 @@ class TestSymbolDatabase : public TestFixture { TEST_CASE(auto18); TEST_CASE(auto19); TEST_CASE(auto20); + TEST_CASE(auto21); TEST_CASE(unionWithConstructor); @@ -5716,8 +5717,7 @@ class TestSymbolDatabase : public TestFixture { ASSERT_EQUALS(E1->value, 1); const Token* const a = Token::findsimplematch(tokenizer.tokens(), "auto"); ASSERT(a && a->valueType()); - TODO_ASSERT(E1->scope == a->valueType()->typeScope); - ASSERT_EQUALS(a->valueType()->type, ValueType::INT); + ASSERT(E1->scope == a->valueType()->typeScope); } void sizeOfType() { @@ -9399,7 +9399,6 @@ class TestSymbolDatabase : public TestFixture { ASSERT(autoTok && autoTok->valueType()); ASSERT_EQUALS(autoTok->valueType()->constness, 3); ASSERT_EQUALS(autoTok->valueType()->pointer, 1); - TODO_ASSERT(autoTok->valueType()->reference == Reference::LValue); } void auto19() { // #11517 @@ -9454,6 +9453,23 @@ class TestSymbolDatabase : public TestFixture { ASSERT_EQUALS(g->function()->tokenDef->linenr(), 4); } + void auto21() { + GET_SYMBOL_DB("int f(bool b) {\n" + " std::vector v1(1), v2(2);\n" + " auto& v = b ? v1 : v2;\n" + " v.push_back(1);\n" + " return v.size();\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + const Token* a = Token::findsimplematch(tokenizer.tokens(), "auto"); + ASSERT(a && a->valueType()); + ASSERT_EQUALS(a->valueType()->type, ValueType::CONTAINER); + const Token* v = Token::findsimplematch(a, "v . size"); + ASSERT(v && v->valueType()); + ASSERT_EQUALS(v->valueType()->type, ValueType::CONTAINER); + ASSERT(v->variable() && v->variable()->isReference()); + } + void unionWithConstructor() { GET_SYMBOL_DB("union Fred {\n" " Fred(int x) : i(x) { }\n" From 33dee83c21d6f30905f984770bfc698ee72d30b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Fri, 18 Aug 2023 11:55:23 +0200 Subject: [PATCH 22/30] moved suppression-specific code out of `ErrorLogger` (#5329) --- Makefile | 8 +++--- cli/cppcheckexecutor.cpp | 6 ++-- cli/cppcheckexecutor.h | 6 ++-- lib/cppcheck.cpp | 4 +-- lib/errorlogger.cpp | 49 -------------------------------- lib/errorlogger.h | 10 ------- lib/suppressions.cpp | 51 ++++++++++++++++++++++++++++++++- lib/suppressions.h | 10 +++++++ test/testerrorlogger.cpp | 59 -------------------------------------- test/testsuppressions.cpp | 60 +++++++++++++++++++++++++++++++++++++++ 10 files changed, 133 insertions(+), 130 deletions(-) diff --git a/Makefile b/Makefile index 5d7931f9a94..aec9288fe31 100644 --- a/Makefile +++ b/Makefile @@ -455,7 +455,7 @@ validateRules: ###### Build -$(libcppdir)/analyzerinfo.o: lib/analyzerinfo.cpp externals/tinyxml2/tinyxml2.h lib/analyzerinfo.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/path.h lib/platform.h lib/suppressions.h lib/utils.h +$(libcppdir)/analyzerinfo.o: lib/analyzerinfo.cpp externals/tinyxml2/tinyxml2.h lib/analyzerinfo.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/path.h lib/platform.h lib/utils.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/analyzerinfo.cpp $(libcppdir)/astutils.o: lib/astutils.cpp lib/astutils.h lib/check.h lib/checkclass.h lib/config.h lib/errortypes.h lib/importproject.h lib/infer.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vfvalue.h @@ -641,10 +641,10 @@ cli/cmdlineparser.o: cli/cmdlineparser.cpp cli/cmdlineparser.h cli/cppcheckexecu cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cmdlineparser.h cli/cppcheckexecutor.h cli/cppcheckexecutorseh.h cli/cppcheckexecutorsig.h cli/executor.h cli/filelister.h cli/processexecutor.h cli/singleexecutor.h cli/threadexecutor.h lib/analyzerinfo.h lib/check.h lib/checkunusedfunctions.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/cppcheckexecutor.cpp -cli/cppcheckexecutorseh.o: cli/cppcheckexecutorseh.cpp cli/cppcheckexecutor.h cli/cppcheckexecutorseh.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/suppressions.h lib/utils.h +cli/cppcheckexecutorseh.o: cli/cppcheckexecutorseh.cpp cli/cppcheckexecutor.h cli/cppcheckexecutorseh.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/cppcheckexecutorseh.cpp -cli/cppcheckexecutorsig.o: cli/cppcheckexecutorsig.cpp cli/cppcheckexecutor.h cli/cppcheckexecutorsig.h cli/stacktrace.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/suppressions.h +cli/cppcheckexecutorsig.o: cli/cppcheckexecutorsig.cpp cli/cppcheckexecutor.h cli/cppcheckexecutorsig.h cli/stacktrace.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/cppcheckexecutorsig.cpp cli/executor.o: cli/executor.cpp cli/executor.h 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/utils.h @@ -653,7 +653,7 @@ cli/executor.o: cli/executor.cpp cli/executor.h lib/color.h lib/config.h lib/err cli/filelister.o: cli/filelister.cpp cli/filelister.h lib/config.h lib/path.h lib/pathmatch.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/filelister.cpp -cli/main.o: cli/main.cpp cli/cppcheckexecutor.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/suppressions.h +cli/main.o: cli/main.cpp cli/cppcheckexecutor.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/main.cpp cli/processexecutor.o: cli/processexecutor.cpp cli/cppcheckexecutor.h cli/executor.h cli/processexecutor.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.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/utils.h diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index eabf0582022..540619939e2 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -261,11 +261,11 @@ bool CppCheckExecutor::reportSuppressions(const Settings &settings, bool unusedF bool err = false; if (settings.useSingleJob()) { for (std::map::const_iterator i = files.cbegin(); i != files.cend(); ++i) { - err |= errorLogger.reportUnmatchedSuppressions( - settings.nomsg.getUnmatchedLocalSuppressions(i->first, unusedFunctionCheckEnabled)); + err |= Suppressions::reportUnmatchedSuppressions( + settings.nomsg.getUnmatchedLocalSuppressions(i->first, unusedFunctionCheckEnabled), errorLogger); } } - err |= errorLogger.reportUnmatchedSuppressions(settings.nomsg.getUnmatchedGlobalSuppressions(unusedFunctionCheckEnabled)); + err |= Suppressions::reportUnmatchedSuppressions(settings.nomsg.getUnmatchedGlobalSuppressions(unusedFunctionCheckEnabled), errorLogger); return err; } diff --git a/cli/cppcheckexecutor.h b/cli/cppcheckexecutor.h index 23e845e0e6f..e5577396d75 100644 --- a/cli/cppcheckexecutor.h +++ b/cli/cppcheckexecutor.h @@ -43,6 +43,8 @@ class Settings; */ class CppCheckExecutor : public ErrorLogger { public: + friend class TestSuppressions; + /** * Constructor */ @@ -101,8 +103,6 @@ class CppCheckExecutor : public ErrorLogger { */ static bool executeCommand(std::string exe, std::vector args, std::string redirect, std::string &output_); - static bool reportSuppressions(const Settings &settings, bool unusedFunctionCheckEnabled, const std::map &files, ErrorLogger& errorLogger); - protected: /** @@ -124,6 +124,8 @@ class CppCheckExecutor : public ErrorLogger { private: + static bool reportSuppressions(const Settings &settings, bool unusedFunctionCheckEnabled, const std::map &files, ErrorLogger& errorLogger); + /** * Wrapper around check_internal * - installs optional platform dependent signal handling diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index f336630bcd1..11b4db07c90 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -1021,7 +1021,7 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string // In jointSuppressionReport mode, unmatched suppressions are // collected after all files are processed if (!mSettings.useSingleJob() && (mSettings.severity.isEnabled(Severity::information) || mSettings.checkConfiguration)) { - reportUnmatchedSuppressions(mSettings.nomsg.getUnmatchedLocalSuppressions(filename, isUnusedFunctionCheckEnabled())); + Suppressions::reportUnmatchedSuppressions(mSettings.nomsg.getUnmatchedLocalSuppressions(filename, isUnusedFunctionCheckEnabled()), *this); } mErrorList.clear(); @@ -1597,7 +1597,7 @@ void CppCheck::reportErr(const ErrorMessage &msg) mAnalyzerInformation.reportErr(msg); // TODO: only convert if necessary - const Suppressions::ErrorMessage errorMessage = msg.toSuppressionsErrorMessage(); + const auto errorMessage = Suppressions::ErrorMessage::fromErrorMessage(msg); if (mSettings.nomsg.isSuppressed(errorMessage, mUseGlobalSuppressions)) { return; diff --git a/lib/errorlogger.cpp b/lib/errorlogger.cpp index f6454e1d569..16010663e3e 100644 --- a/lib/errorlogger.cpp +++ b/lib/errorlogger.cpp @@ -211,22 +211,6 @@ void ErrorMessage::setmsg(const std::string &msg) } } -Suppressions::ErrorMessage ErrorMessage::toSuppressionsErrorMessage() const -{ - Suppressions::ErrorMessage ret; - ret.hash = hash; - ret.errorId = id; - if (!callStack.empty()) { - ret.setFileName(callStack.back().getfile(false)); - ret.lineNumber = callStack.back().line; - } else { - ret.lineNumber = Suppressions::Suppression::NO_LINE; - } - ret.certainty = certainty; - ret.symbolNames = mSymbolNames; - return ret; -} - static void serializeString(std::string &oss, const std::string & str) { oss += std::to_string(str.length()); @@ -681,39 +665,6 @@ std::string ErrorMessage::toString(bool verbose, const std::string &templateForm return result; } -bool ErrorLogger::reportUnmatchedSuppressions(const std::list &unmatched) -{ - bool err = false; - // Report unmatched suppressions - for (const Suppressions::Suppression &s : unmatched) { - // don't report "unmatchedSuppression" as unmatched - if (s.errorId == "unmatchedSuppression") - continue; - - // check if this unmatched suppression is suppressed - bool suppressed = false; - for (const Suppressions::Suppression &s2 : unmatched) { - if (s2.errorId == "unmatchedSuppression") { - if ((s2.fileName.empty() || s2.fileName == "*" || s2.fileName == s.fileName) && - (s2.lineNumber == Suppressions::Suppression::NO_LINE || s2.lineNumber == s.lineNumber)) { - suppressed = true; - break; - } - } - } - - if (suppressed) - continue; - - std::list callStack; - if (!s.fileName.empty()) - callStack.emplace_back(s.fileName, s.lineNumber, 0); - reportErr(ErrorMessage(callStack, emptyString, Severity::information, "Unmatched suppression: " + s.errorId, "unmatchedSuppression", Certainty::normal)); - err = true; - } - return err; -} - std::string ErrorLogger::callStackToString(const std::list &callStack) { std::string str; diff --git a/lib/errorlogger.h b/lib/errorlogger.h index 4cb1352c2c1..d9983df1b42 100644 --- a/lib/errorlogger.h +++ b/lib/errorlogger.h @@ -23,7 +23,6 @@ #include "config.h" #include "errortypes.h" -#include "suppressions.h" #include "color.h" #include @@ -198,8 +197,6 @@ class CPPCHECKLIB ErrorMessage { return mSymbolNames; } - Suppressions::ErrorMessage toSuppressionsErrorMessage() const; - private: static std::string fixInvalidChars(const std::string& raw); @@ -250,13 +247,6 @@ class CPPCHECKLIB ErrorLogger { (void)value; } - /** - * Report unmatched suppressions - * @param unmatched list of unmatched suppressions (from Settings::Suppressions::getUnmatched(Local|Global)Suppressions) - * @return true is returned if errors are reported - */ - bool reportUnmatchedSuppressions(const std::list &unmatched); - static std::string callStackToString(const std::list &callStack); /** diff --git a/lib/suppressions.cpp b/lib/suppressions.cpp index ca5676e04f1..eac6ae6cf39 100644 --- a/lib/suppressions.cpp +++ b/lib/suppressions.cpp @@ -35,6 +35,22 @@ #include +Suppressions::ErrorMessage Suppressions::ErrorMessage::fromErrorMessage(const ::ErrorMessage &msg) +{ + Suppressions::ErrorMessage ret; + ret.hash = msg.hash; + ret.errorId = msg.id; + if (!msg.callStack.empty()) { + ret.setFileName(msg.callStack.back().getfile(false)); + ret.lineNumber = msg.callStack.back().line; + } else { + ret.lineNumber = Suppressions::Suppression::NO_LINE; + } + ret.certainty = msg.certainty; + ret.symbolNames = msg.symbolNames(); + return ret; +} + static bool isAcceptedErrorIdChar(char c) { switch (c) { @@ -384,7 +400,7 @@ bool Suppressions::isSuppressed(const ::ErrorMessage &errmsg) { if (mSuppressions.empty()) return false; - return isSuppressed(errmsg.toSuppressionsErrorMessage()); + return isSuppressed(Suppressions::ErrorMessage::fromErrorMessage(errmsg)); } void Suppressions::dump(std::ostream & out) const @@ -461,3 +477,36 @@ void Suppressions::markUnmatchedInlineSuppressionsAsChecked(const Tokenizer &tok } } } + +bool Suppressions::reportUnmatchedSuppressions(const std::list &unmatched, ErrorLogger &errorLogger) +{ + bool err = false; + // Report unmatched suppressions + for (const Suppressions::Suppression &s : unmatched) { + // don't report "unmatchedSuppression" as unmatched + if (s.errorId == "unmatchedSuppression") + continue; + + // check if this unmatched suppression is suppressed + bool suppressed = false; + for (const Suppressions::Suppression &s2 : unmatched) { + if (s2.errorId == "unmatchedSuppression") { + if ((s2.fileName.empty() || s2.fileName == "*" || s2.fileName == s.fileName) && + (s2.lineNumber == Suppressions::Suppression::NO_LINE || s2.lineNumber == s.lineNumber)) { + suppressed = true; + break; + } + } + } + + if (suppressed) + continue; + + std::list<::ErrorMessage::FileLocation> callStack; + if (!s.fileName.empty()) + callStack.emplace_back(s.fileName, s.lineNumber, 0); + errorLogger.reportErr(::ErrorMessage(callStack, emptyString, Severity::information, "Unmatched suppression: " + s.errorId, "unmatchedSuppression", Certainty::normal)); + err = true; + } + return err; +} diff --git a/lib/suppressions.h b/lib/suppressions.h index cc64ee51cef..6e1fd9c9e52 100644 --- a/lib/suppressions.h +++ b/lib/suppressions.h @@ -34,6 +34,7 @@ class Tokenizer; class ErrorMessage; +class ErrorLogger; enum class Certainty; /** @brief class for handling suppressions */ @@ -50,6 +51,8 @@ class CPPCHECKLIB Suppressions { int lineNumber; Certainty certainty; std::string symbolNames; + + static Suppressions::ErrorMessage fromErrorMessage(const ::ErrorMessage &msg); private: std::string mFileName; }; @@ -201,6 +204,13 @@ class CPPCHECKLIB Suppressions { */ void markUnmatchedInlineSuppressionsAsChecked(const Tokenizer &tokenizer); + /** + * Report unmatched suppressions + * @param unmatched list of unmatched suppressions (from Settings::Suppressions::getUnmatched(Local|Global)Suppressions) + * @return true is returned if errors are reported + */ + static bool reportUnmatchedSuppressions(const std::list &unmatched, ErrorLogger &errorLogger); + private: /** @brief List of error which the user doesn't want to see. */ std::list mSuppressions; diff --git a/test/testerrorlogger.cpp b/test/testerrorlogger.cpp index 481f67bb7a7..14de5539047 100644 --- a/test/testerrorlogger.cpp +++ b/test/testerrorlogger.cpp @@ -61,7 +61,6 @@ class TestErrorLogger : public TestFixture { TEST_CASE(SerializeSanitize); TEST_CASE(SerializeFileLocation); - TEST_CASE(suppressUnmatchedSuppressions); TEST_CASE(substituteTemplateFormatStatic); TEST_CASE(substituteTemplateLocationStatic); } @@ -425,64 +424,6 @@ class TestErrorLogger : public TestFixture { ASSERT_EQUALS("abcd:/,", msg2.callStack.front().getinfo()); } - void suppressUnmatchedSuppressions() { - std::list suppressions; - - // No unmatched suppression - errout.str(""); - suppressions.clear(); - reportUnmatchedSuppressions(suppressions); - ASSERT_EQUALS("", errout.str()); - - // suppress all unmatchedSuppression - errout.str(""); - suppressions.clear(); - suppressions.emplace_back("abc", "a.c", 10U); - suppressions.emplace_back("unmatchedSuppression", "*", Suppressions::Suppression::NO_LINE); - reportUnmatchedSuppressions(suppressions); - ASSERT_EQUALS("", errout.str()); - - // suppress all unmatchedSuppression (corresponds to "--suppress=unmatchedSuppression") - errout.str(""); - suppressions.clear(); - suppressions.emplace_back("abc", "a.c", 10U); - suppressions.emplace_back("unmatchedSuppression", "", Suppressions::Suppression::NO_LINE); - reportUnmatchedSuppressions(suppressions); - ASSERT_EQUALS("", errout.str()); - - // suppress all unmatchedSuppression in a.c - errout.str(""); - suppressions.clear(); - suppressions.emplace_back("abc", "a.c", 10U); - suppressions.emplace_back("unmatchedSuppression", "a.c", Suppressions::Suppression::NO_LINE); - reportUnmatchedSuppressions(suppressions); - ASSERT_EQUALS("", errout.str()); - - // suppress unmatchedSuppression in a.c at line 10 - errout.str(""); - suppressions.clear(); - suppressions.emplace_back("abc", "a.c", 10U); - suppressions.emplace_back("unmatchedSuppression", "a.c", 10U); - reportUnmatchedSuppressions(suppressions); - ASSERT_EQUALS("", errout.str()); - - // don't suppress unmatchedSuppression when file is mismatching - errout.str(""); - suppressions.clear(); - suppressions.emplace_back("abc", "a.c", 10U); - suppressions.emplace_back("unmatchedSuppression", "b.c", Suppressions::Suppression::NO_LINE); - reportUnmatchedSuppressions(suppressions); - ASSERT_EQUALS("[a.c:10]: (information) Unmatched suppression: abc\n", errout.str()); - - // don't suppress unmatchedSuppression when line is mismatching - errout.str(""); - suppressions.clear(); - suppressions.emplace_back("abc", "a.c", 10U); - suppressions.emplace_back("unmatchedSuppression", "a.c", 1U); - reportUnmatchedSuppressions(suppressions); - ASSERT_EQUALS("[a.c:10]: (information) Unmatched suppression: abc\n", errout.str()); - } - void substituteTemplateFormatStatic() const { { diff --git a/test/testsuppressions.cpp b/test/testsuppressions.cpp index f1c6a7d8a47..19fdf307c14 100644 --- a/test/testsuppressions.cpp +++ b/test/testsuppressions.cpp @@ -83,6 +83,8 @@ class TestSuppressions : public TestFixture { TEST_CASE(suppressingSyntaxErrorAndExitCode); TEST_CASE(suppressLocal); + + TEST_CASE(suppressUnmatchedSuppressions); } void suppressionsBadId1() const { @@ -859,6 +861,64 @@ class TestSuppressions : public TestFixture { ASSERT_EQUALS(true, suppressions.isSuppressed(errorMessage("errorid2", "test2.cpp", 1))); ASSERT_EQUALS(false, suppressions.isSuppressed(errorMessage("errorid2", "test2.cpp", 1), false)); } + + void suppressUnmatchedSuppressions() { + std::list suppressions; + + // No unmatched suppression + errout.str(""); + suppressions.clear(); + Suppressions::reportUnmatchedSuppressions(suppressions, *this); + ASSERT_EQUALS("", errout.str()); + + // suppress all unmatchedSuppression + errout.str(""); + suppressions.clear(); + suppressions.emplace_back("abc", "a.c", 10U); + suppressions.emplace_back("unmatchedSuppression", "*", Suppressions::Suppression::NO_LINE); + Suppressions::reportUnmatchedSuppressions(suppressions, *this); + ASSERT_EQUALS("", errout.str()); + + // suppress all unmatchedSuppression (corresponds to "--suppress=unmatchedSuppression") + errout.str(""); + suppressions.clear(); + suppressions.emplace_back("abc", "a.c", 10U); + suppressions.emplace_back("unmatchedSuppression", "", Suppressions::Suppression::NO_LINE); + Suppressions::reportUnmatchedSuppressions(suppressions, *this); + ASSERT_EQUALS("", errout.str()); + + // suppress all unmatchedSuppression in a.c + errout.str(""); + suppressions.clear(); + suppressions.emplace_back("abc", "a.c", 10U); + suppressions.emplace_back("unmatchedSuppression", "a.c", Suppressions::Suppression::NO_LINE); + Suppressions::reportUnmatchedSuppressions(suppressions, *this); + ASSERT_EQUALS("", errout.str()); + + // suppress unmatchedSuppression in a.c at line 10 + errout.str(""); + suppressions.clear(); + suppressions.emplace_back("abc", "a.c", 10U); + suppressions.emplace_back("unmatchedSuppression", "a.c", 10U); + Suppressions::reportUnmatchedSuppressions(suppressions, *this); + ASSERT_EQUALS("", errout.str()); + + // don't suppress unmatchedSuppression when file is mismatching + errout.str(""); + suppressions.clear(); + suppressions.emplace_back("abc", "a.c", 10U); + suppressions.emplace_back("unmatchedSuppression", "b.c", Suppressions::Suppression::NO_LINE); + Suppressions::reportUnmatchedSuppressions(suppressions, *this); + ASSERT_EQUALS("[a.c:10]: (information) Unmatched suppression: abc\n", errout.str()); + + // don't suppress unmatchedSuppression when line is mismatching + errout.str(""); + suppressions.clear(); + suppressions.emplace_back("abc", "a.c", 10U); + suppressions.emplace_back("unmatchedSuppression", "a.c", 1U); + Suppressions::reportUnmatchedSuppressions(suppressions, *this); + ASSERT_EQUALS("[a.c:10]: (information) Unmatched suppression: abc\n", errout.str()); + } }; REGISTER_TEST(TestSuppressions) From c7f88db90a0eb5d185901826f473ba8a9a0c2f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Fri, 18 Aug 2023 11:59:14 +0200 Subject: [PATCH 23/30] CmdLineParser: deprecated `--template