diff --git a/rules/error-reporting.xml b/rules/error-reporting.xml deleted file mode 100644 index 2813c9bba65..00000000000 --- a/rules/error-reporting.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - Severity :: fromString \( "\w+" \) - - ConstantSeverityFromString - style - Constant severity lookups should be done via -Severity::constant. - - diff --git a/rules/token-matching.xml b/rules/token-matching.xml deleted file mode 100644 index 8b7823c05da..00000000000 --- a/rules/token-matching.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - Token :: (?:findm|(?:simple|)M)atch \([^,]+,\s+"(?:\s+|[^"]+?\s+") - - TokenMatchSpacing - style - Useless extra spacing for Token::*Match. - - - - (?U)Token :: Match \([^,]+,\s+"[^%|!\[\]]+" \) - - UseTokensimpleMatch - error - Token::simpleMatch should be used to match tokens without special pattern requirements. - - - - \b[\w_]+ \. tokAt \( 0 \) - - TokentokAt0 - error - tok->tokAt(0) is a slow way to say tok. - - - - \b[\w_]+ \. strAt \( 0 \) - - TokenstrAt0 - error - tok->strAt(0) is a slow way to say tok->str() - - - - - - TokenMatchVariable - error - Simplify 'Token :: Match ( expr , %var% ) && expr->variable()' to 'expr->variable()' - - - diff --git a/test/cli/rules_test.py b/test/cli/rules_test.py new file mode 100644 index 00000000000..241cdf34c51 --- /dev/null +++ b/test/cli/rules_test.py @@ -0,0 +1,186 @@ +import os +import sys + +from testutils import cppcheck + +__script_dir = os.path.dirname(os.path.abspath(__file__)) +__root_dir = os.path.abspath(os.path.join(__script_dir, '..', '..')) +__rules_dir = os.path.join(__root_dir, 'rules') + + +def test_empty_catch_block(tmp_path): + test_file = tmp_path / 'test.cpp' + with open(test_file, 'wt') as f: + f.write(""" +void f() +{ + try + { + } + catch (...) + { + } +} +""") + + rule_file = os.path.join(__rules_dir, 'empty-catch-block.xml') + args = [ + '--template=simple', + '--rule-file={}'.format(rule_file), + str(test_file) + ] + ret, stdout, stderr = cppcheck(args) + assert ret == 0 + assert stdout.splitlines() == [ + 'Checking {} ...'.format(test_file), + 'Processing rule: \\}\\s*catch\\s*\\(.*\\)\\s*\\{\\s*\\}' + ] + assert stderr.splitlines() == [ + '{}:6:0: style: Empty catch block found. [rule]'.format(test_file) + ] + + +def test_show_all_defines(tmp_path): + test_file = tmp_path / 'test.cpp' + with open(test_file, 'wt') as f: + f.write(""" +#define DEF_1 + +void f() +{ +} +""") + + rule_file = os.path.join(__rules_dir, 'show-all-defines.rule') + args = [ + '--template=simple', + '-DDEF_2', + '--rule-file={}'.format(rule_file), + str(test_file) + ] + ret, stdout, stderr = cppcheck(args) + assert ret == 0 + assert stdout.splitlines() == [ + 'Checking {} ...'.format(test_file), + 'Processing rule: .*', + 'Checking {}: DEF_2=1...'.format(test_file) + ] + if sys.platform == 'win32': + test_file = str(test_file).replace('\\', '/') + assert stderr.splitlines() == [ + # TODO: this message looks strange + ":1:0: information: found ' # line 2 \"{}\" # define DEF_1' [showalldefines]".format(test_file) + ] + + +def test_stl(tmp_path): + test_file = tmp_path / 'test.cpp' + with open(test_file, 'wt') as f: + f.write(""" +void f() +{ + std::string s; + if (s.find("t") == 17) + { + } +} +""") + + rule_file = os.path.join(__rules_dir, 'stl.xml') + args = [ + '--template=simple', + '--rule-file={}'.format(rule_file), + str(test_file) + ] + ret, stdout, stderr = cppcheck(args) + assert ret == 0 + assert stdout.splitlines() == [ + 'Checking {} ...'.format(test_file), + 'Processing rule: \\. find \\( "[^"]+?" \\) == \\d+ ' + ] + assert stderr.splitlines() == [ + '{}:5:0: performance: When looking for a string at a fixed position compare [UselessSTDStringFind]'.format(test_file) + ] + + +def test_strlen_empty_str(tmp_path): + test_file = tmp_path / 'test.cpp' + with open(test_file, 'wt') as f: + f.write(""" +void f(const char* s) +{ + if (strlen(s) > 0) + { + } +} +""") + + rule_file = os.path.join(__rules_dir, 'strlen-empty-str.xml') + args = [ + '--template=simple', + '--rule-file={}'.format(rule_file), + str(test_file) + ] + ret, stdout, stderr = cppcheck(args) + assert ret == 0 + assert stdout.splitlines() == [ + 'Checking {} ...'.format(test_file), + 'Processing rule: if \\( ([!] )*?(strlen) \\( \\w+? \\) ([>] [0] )*?\\) { ' + ] + assert stderr.splitlines() == [ + '{}:4:0: performance: Using strlen() to check if a string is empty is not efficient. [StrlenEmptyString]'.format(test_file) + ] + + +def test_suggest_nullptr(tmp_path): + test_file = tmp_path / 'test.cpp' + with open(test_file, 'wt') as f: + f.write(""" +void f() +{ + const char* p = 0; +} +""") + + rule_file = os.path.join(__rules_dir, 'suggest_nullptr.xml') + args = [ + '--template=simple', + '--rule-file={}'.format(rule_file), + str(test_file) + ] + ret, stdout, stderr = cppcheck(args) + assert ret == 0 + assert stdout.splitlines() == [ + 'Checking {} ...'.format(test_file), + 'Processing rule: (\\b\\w+\\b) \\* (\\b\\w+\\b) = 0 ;' + ] + assert stderr.splitlines() == [ + "{}:4:0: style: Prefer to use a 'nullptr' instead of initializing a pointer with 0. [modernizeUseNullPtr]".format(test_file) + ] + + +def test_unused_deref(tmp_path): + test_file = tmp_path / 'test.cpp' + with open(test_file, 'wt') as f: + f.write(""" +void f(const char* p) +{ + *p++; +} +""") + + rule_file = os.path.join(__rules_dir, 'unused-deref.xml') + args = [ + '--template=simple', + '--rule-file={}'.format(rule_file), + str(test_file) + ] + ret, stdout, stderr = cppcheck(args) + assert ret == 0 + assert stdout.splitlines() == [ + 'Checking {} ...'.format(test_file), + 'Processing rule: [;{}] [*] \\w+? (\\+\\+|\\-\\-) ; ' + ] + assert stderr.splitlines() == [ + '{}:3:0: style: Redundant * found, "*p++" is the same as "*(p++)". [UnusedDeref]'.format(test_file) + ]