From fe04c15c9ec4bcb7bbcb404205022c2b064d535b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 5 May 2019 10:35:22 +0200 Subject: [PATCH] CheckStl: Modernize the recommendations. string::starts_with is more intuitive than string::compare --- cli/cmdlineparser.cpp | 6 +++++- lib/checkstl.cpp | 10 +++++----- lib/standards.h | 8 ++++++-- test/teststl.cpp | 12 ++++++------ 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index a9c97c892..fdecb079d 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -612,6 +612,8 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) mSettings->standards.cpp = Standards::CPP14; } else if (std::strcmp(argv[i], "--std=c++17") == 0) { mSettings->standards.cpp = Standards::CPP17; + } else if (std::strcmp(argv[i], "--std=c++20") == 0) { + mSettings->standards.cpp = Standards::CPP20; } // Output formatter @@ -1103,7 +1105,9 @@ void CmdLineParser::printHelp() " * c++14\n" " C++ code is C++14 compatible\n" " * c++17\n" - " C++ code is C++17 compatible (default)\n" + " C++ code is C++17 compatible\n" + " * c++20\n" + " C++ code is C++20 compatible (default)\n" " --suppress= Suppress warnings that match . The format of\n" " is:\n" " [error id]:[filename]:[line]\n" diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index 2a1f854a7..a4d96a8db 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -1226,14 +1226,14 @@ void CheckStl::if_find() void CheckStl::if_findError(const Token *tok, bool str) { - if (str) + if (str && mSettings->standards.cpp >= Standards::CPP20) reportError(tok, Severity::performance, "stlIfStrFind", - "Inefficient usage of string::find() in condition; string::compare() would be faster.\n" - "Either inefficient or wrong usage of string::find(). string::compare() will be faster if " + "Inefficient usage of string::find() in condition; string::starts_with() would be faster.\n" + "Either inefficient or wrong usage of string::find(). string::starts_with() will be faster if " "string::find's result is compared with 0, because it will not scan the whole " "string. If your intention is to check that there are no findings in the string, " "you should compare with std::string::npos.", CWE597, false); - else + if (!str) reportError(tok, Severity::warning, "stlIfFind", "Suspicious condition. The result of find() is an iterator, but it is not properly checked.", CWE398, false); } @@ -1396,7 +1396,7 @@ void CheckStl::size() if (!mSettings->isEnabled(Settings::PERFORMANCE)) return; - if (mSettings->standards.cpp == Standards::CPP11) + if (mSettings->standards.cpp >= Standards::CPP11) return; const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase(); diff --git a/lib/standards.h b/lib/standards.h index cc75c220d..c90bc0032 100644 --- a/lib/standards.h +++ b/lib/standards.h @@ -36,10 +36,10 @@ struct Standards { enum cstd_t { C89, C99, C11, CLatest=C11 } c; /** C++ code standard */ - enum cppstd_t { CPP03, CPP11, CPP14, CPP17, CPPLatest=CPP17 } cpp; + enum cppstd_t { CPP03, CPP11, CPP14, CPP17, CPP20, CPPLatest=CPP20 } cpp; /** This constructor clear all the variables **/ - Standards() : c(C11), cpp(CPP17) {} + Standards() : c(C11), cpp(CPPLatest) {} bool setC(const std::string& str) { if (str == "c89" || str == "C89") { @@ -73,6 +73,10 @@ struct Standards { cpp = CPP17; return true; } + if (str == "c++20" || str == "C++20") { + cpp = CPP20; + return true; + } return false; } }; diff --git a/test/teststl.cpp b/test/teststl.cpp index 2c8fe304a..b83e675ea 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -159,7 +159,7 @@ private: TEST_CASE(findInsert); } - void check(const char code[], const bool inconclusive=false, const Standards::cppstd_t cppstandard=Standards::CPP11) { + void check(const char code[], const bool inconclusive=false, const Standards::cppstd_t cppstandard=Standards::CPPLatest) { // Clear the error buffer.. errout.str(""); @@ -2391,35 +2391,35 @@ private: "{\n" " if (s.find(\"abc\")) { }\n" "}"); - ASSERT_EQUALS("[test.cpp:3]: (performance) Inefficient usage of string::find() in condition; string::compare() would be faster.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (performance) Inefficient usage of string::find() in condition; string::starts_with() would be faster.\n", errout.str()); // error (pointer) check("void f(const std::string *s)\n" "{\n" " if ((*s).find(\"abc\")) { }\n" "}"); - ASSERT_EQUALS("[test.cpp:3]: (performance) Inefficient usage of string::find() in condition; string::compare() would be faster.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (performance) Inefficient usage of string::find() in condition; string::starts_with() would be faster.\n", errout.str()); // error (pointer) check("void f(const std::string *s)\n" "{\n" " if (s->find(\"abc\")) { }\n" "}"); - ASSERT_EQUALS("[test.cpp:3]: (performance) Inefficient usage of string::find() in condition; string::compare() would be faster.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (performance) Inefficient usage of string::find() in condition; string::starts_with() would be faster.\n", errout.str()); // error (vector) check("void f(const std::vector &s)\n" "{\n" " if (s[0].find(\"abc\")) { }\n" "}"); - ASSERT_EQUALS("[test.cpp:3]: (performance) Inefficient usage of string::find() in condition; string::compare() would be faster.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (performance) Inefficient usage of string::find() in condition; string::starts_with() would be faster.\n", errout.str()); // #3162 check("void f(const std::string& s1, const std::string& s2)\n" "{\n" " if ((!s1.empty()) && (0 == s1.find(s2))) { }\n" "}"); - ASSERT_EQUALS("[test.cpp:3]: (performance) Inefficient usage of string::find() in condition; string::compare() would be faster.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (performance) Inefficient usage of string::find() in condition; string::starts_with() would be faster.\n", errout.str()); // #4102 check("void f(const std::string &define) {\n"