From a26b16d6d0fad55de21224142a9d716a8a6d8af0 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 6 May 2024 14:19:59 +0200 Subject: [PATCH 1/5] Fix #12712 FN duplicateCondition with function in namespace (#6386) --- lib/astutils.cpp | 2 -- test/testcondition.cpp | 6 ++++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 348f9ec641c..35a375d414d 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -1684,8 +1684,6 @@ bool isSameExpression(bool macro, const Token *tok1, const Token *tok2, const Se return false; } else { const Token * ftok = tok1; - if (Token::simpleMatch(tok1->previous(), "::")) - ftok = tok1->previous(); if (!settings.library.isFunctionConst(ftok) && !ftok->isAttributeConst() && !ftok->isAttributePure()) return false; } diff --git a/test/testcondition.cpp b/test/testcondition.cpp index 9222c4f27f0..db044308c71 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -5558,6 +5558,12 @@ class TestCondition : public TestFixture { "}\n"); ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:6]: (style) The if condition is the same as the previous if condition\n", errout_str()); + check("void f(double d) {\n" // #12712 + " if (std::isfinite(d)) {}\n" + " if (std::isfinite(d)) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (style) The if condition is the same as the previous if condition\n", errout_str()); + // do not crash check("void assign(const MMA& other) {\n" " if (mPA.cols != other.mPA.cols || mPA.rows != other.mPA.rows)\n" From f562ff2c9c767415c66901f171fda8ab08bd3da0 Mon Sep 17 00:00:00 2001 From: Vladimir Petrigo Date: Tue, 7 May 2024 22:45:38 +0200 Subject: [PATCH 2/5] Make htmlreport installable single package (#6335) For example, with `pipx` you can install `cppcheck-htmlreport` executable as follow: ```py pipx install "git+https://github.com/vpetrigo/cppcheck@feature/installable_htmlreport#subdirectory=htmlreport" ``` That also allows populating `Pygments` into user's environment automatically. No need to switch to the `htmlreport` and execute `pip install .` or something. After that the user is able to use `cppcheck-htmlreport` without installation of DEB/RPM packages. Moreover, on Windows it allows usage of this utility withot necessity to execute it like that, because shebans are not supported there: ```bash python /cppcheck-htmlreport ``` --- .github/workflows/scriptcheck.yml | 19 ++++++++-- .gitignore | 8 ++++ htmlreport/cppcheck-htmlreport | 6 ++- htmlreport/cppcheck_htmlreport/__init__.py | 0 htmlreport/setup.py | 38 ++++++++++++------- htmlreport/test_suppressions.txt | 3 -- htmlreport/tox.ini | 12 ------ .../tools/htmlreport}/check.sh | 21 +++++----- .../tools/htmlreport}/example.cc | 0 .../tools/htmlreport}/example.xml | 0 .../tools/htmlreport}/test_htmlreport.py | 16 +++++--- test/tools/htmlreport/test_suppressions.txt | 3 ++ 12 files changed, 78 insertions(+), 48 deletions(-) create mode 100644 htmlreport/cppcheck_htmlreport/__init__.py delete mode 100644 htmlreport/test_suppressions.txt delete mode 100644 htmlreport/tox.ini rename {htmlreport => test/tools/htmlreport}/check.sh (54%) rename {htmlreport => test/tools/htmlreport}/example.cc (100%) rename {htmlreport => test/tools/htmlreport}/example.xml (100%) rename {htmlreport => test/tools/htmlreport}/test_htmlreport.py (86%) create mode 100644 test/tools/htmlreport/test_suppressions.txt diff --git a/.github/workflows/scriptcheck.yml b/.github/workflows/scriptcheck.yml index 8e6d4859157..307310616bc 100644 --- a/.github/workflows/scriptcheck.yml +++ b/.github/workflows/scriptcheck.yml @@ -143,10 +143,23 @@ jobs: env: PYTHONPATH: ./addons - - name: test htmlreport + - name: test htmlreport (standalone) run: | - htmlreport/test_htmlreport.py - cd htmlreport + test/tools/htmlreport/test_htmlreport.py + cd test/tools/htmlreport + ./check.sh + # Python 3.5 and 3.6 are excluded as they are not supported by setuptools-scm package for getting + # package version + - name: test htmlreport (pip) + if: matrix.python-version != '3.5' && matrix.python-version != '3.6' + run: | + python -m venv venv + source venv/bin/activate + python -m pip install -U pip + pip install ./htmlreport/ + which cppcheck-htmlreport + PIP_PACKAGE_TEST=1 test/tools/htmlreport/test_htmlreport.py + cd test/tools/htmlreport ./check.sh - name: test reduce diff --git a/.gitignore b/.gitignore index 8afdc9611b9..90a97ae5873 100644 --- a/.gitignore +++ b/.gitignore @@ -134,3 +134,11 @@ compile_commands.json /oss-fuzz/corpus /oss-fuzz/corpus_ /oss-fuzz/samples + +# Python +/.venv/ +/venv/ +**/*.egg-info/ + +# cppcheck-htmlreport auto files +/htmlreport/cppcheck_htmlreport/run.py diff --git a/htmlreport/cppcheck-htmlreport b/htmlreport/cppcheck-htmlreport index 8a3686b0d65..411b03551d8 100755 --- a/htmlreport/cppcheck-htmlreport +++ b/htmlreport/cppcheck-htmlreport @@ -616,7 +616,7 @@ class CppCheckHandler(XmlContentHandler): 'info': attributes.get('info') }) -if __name__ == '__main__': +def main() -> None: # Configure all the options this little utility is using. parser = optparse.OptionParser() parser.add_option('--title', dest='title', @@ -984,3 +984,7 @@ if __name__ == '__main__': stats_file.write(HTML_FOOTER % contentHandler.versionCppcheck) print("\nOpen '" + options.report_dir + "/index.html' to see the results.") + + +if __name__ == "__main__": + main() diff --git a/htmlreport/cppcheck_htmlreport/__init__.py b/htmlreport/cppcheck_htmlreport/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/htmlreport/setup.py b/htmlreport/setup.py index ac790fbebc1..3e049181ce6 100755 --- a/htmlreport/setup.py +++ b/htmlreport/setup.py @@ -1,21 +1,31 @@ #!/usr/bin/env python3 +import shutil +from setuptools import find_packages, setup -from setuptools import setup - -with open('README.txt') as f: +with open("README.txt") as f: readme = f.read() +shutil.copy("cppcheck-htmlreport", "cppcheck_htmlreport/run.py") + setup( - name="cppcheck", - description='Python script to parse the XML (version 2) output of ' + - 'cppcheck and generate an HTML report using Pygments for syntax ' + - 'highlighting.', + name="cppcheck-htmlreport", + description=( + "Python script to parse the XML (version 2) output of " + "cppcheck and generate an HTML report using Pygments for syntax " + "highlighting." + ), long_description=readme, - author='Henrik Nilsson', - url='https://github.com/danmar/cppcheck', - license='GPL', - scripts=[ - "cppcheck-htmlreport", - ], - install_requires=['Pygments'] + author="Cppcheck Team", + url="https://github.com/danmar/cppcheck", + license="GPL", + packages=find_packages(exclude=("tests", "docs")), + use_scm_version={"root": ".."}, + entry_points={ + "console_scripts": [ + "cppcheck-htmlreport = cppcheck_htmlreport:run.main", + ] + }, + install_requires=["Pygments"], + # Required by setuptools-scm 7.0 for Python 3.7+ + setup_requires=["setuptools>=60", "setuptools-scm>=7.0"], ) diff --git a/htmlreport/test_suppressions.txt b/htmlreport/test_suppressions.txt deleted file mode 100644 index ec3130c099f..00000000000 --- a/htmlreport/test_suppressions.txt +++ /dev/null @@ -1,3 +0,0 @@ -variableScope:../samples/memleak/good.c -*:../samples/resourceLeak/notexisting.c* -uninitstring:* diff --git a/htmlreport/tox.ini b/htmlreport/tox.ini deleted file mode 100644 index 502ca70c110..00000000000 --- a/htmlreport/tox.ini +++ /dev/null @@ -1,12 +0,0 @@ -[tox] -envlist=py26,py27,py32,pypy - -[testenv] -commands= - python test_htmlreport.py -deps=pygments - -[testenv:py26] -deps= - unittest2 - pygments diff --git a/htmlreport/check.sh b/test/tools/htmlreport/check.sh similarity index 54% rename from htmlreport/check.sh rename to test/tools/htmlreport/check.sh index a4515ec0690..dc9d9970cd6 100755 --- a/htmlreport/check.sh +++ b/test/tools/htmlreport/check.sh @@ -26,6 +26,9 @@ if [ -z "$PYTHON" ]; then PYTHON=python fi +SCRIPT_DIR="$(dirname ${BASH_SOURCE[0]})" +ABSOLUTE_SCRIPT_DIR="$(cd -- ${SCRIPT_DIR} ; pwd -P)" +PROJECT_ROOT_DIR="$(cd -- ${SCRIPT_DIR}/../../../ ; pwd -P)" REPORT_DIR=$(mktemp -d -t htmlreport-XXXXXXXXXX) INDEX_HTML="$REPORT_DIR/index.html" STATS_HTML="$REPORT_DIR/stats.html" @@ -33,42 +36,42 @@ GUI_TEST_XML="$REPORT_DIR/gui_test.xml" ERRORLIST_XML="$REPORT_DIR/errorlist.xml" UNMATCHEDSUPPR_XML="$REPORT_DIR/unmatchedSuppr.xml" -$PYTHON cppcheck-htmlreport --file ../gui/test/data/xmlfiles/xmlreport_v2.xml --title "xml2 test" --report-dir "$REPORT_DIR" --source-dir ../test/ +$PYTHON ${PROJECT_ROOT_DIR}/htmlreport/cppcheck-htmlreport --file ${PROJECT_ROOT_DIR}/gui/test/data/xmlfiles/xmlreport_v2.xml --title "xml2 test" --report-dir "$REPORT_DIR" --source-dir ${PROJECT_ROOT_DIR}/test/ echo -e "\n" # Check HTML syntax validate_html "$INDEX_HTML" validate_html "$STATS_HTML" -../cppcheck ../samples --enable=all --inconclusive --xml-version=2 2> "$GUI_TEST_XML" +${PROJECT_ROOT_DIR}/cppcheck ${PROJECT_ROOT_DIR}/samples --enable=all --inconclusive --xml-version=2 2> "$GUI_TEST_XML" xmllint --noout "$GUI_TEST_XML" -$PYTHON cppcheck-htmlreport --file "$GUI_TEST_XML" --title "xml2 + inconclusive test" --report-dir "$REPORT_DIR" +$PYTHON ${PROJECT_ROOT_DIR}/htmlreport/cppcheck-htmlreport --file "$GUI_TEST_XML" --title "xml2 + inconclusive test" --report-dir "$REPORT_DIR" echo "" # Check HTML syntax validate_html "$INDEX_HTML" validate_html "$STATS_HTML" -../cppcheck ../samples --enable=all --inconclusive --verbose --xml-version=2 2> "$GUI_TEST_XML" +${PROJECT_ROOT_DIR}/cppcheck ${PROJECT_ROOT_DIR}/samples --enable=all --inconclusive --verbose --xml-version=2 2> "$GUI_TEST_XML" xmllint --noout "$GUI_TEST_XML" -$PYTHON cppcheck-htmlreport --file "$GUI_TEST_XML" --title "xml2 + inconclusive + verbose test" --report-dir "$REPORT_DIR" +$PYTHON ${PROJECT_ROOT_DIR}/htmlreport/cppcheck-htmlreport --file "$GUI_TEST_XML" --title "xml2 + inconclusive + verbose test" --report-dir "$REPORT_DIR" echo -e "\n" # Check HTML syntax validate_html "$INDEX_HTML" validate_html "$STATS_HTML" -../cppcheck --errorlist --inconclusive --xml-version=2 > "$ERRORLIST_XML" +${PROJECT_ROOT_DIR}/cppcheck --errorlist --inconclusive --xml-version=2 > "$ERRORLIST_XML" xmllint --noout "$ERRORLIST_XML" -$PYTHON cppcheck-htmlreport --file "$ERRORLIST_XML" --title "errorlist" --report-dir "$REPORT_DIR" +$PYTHON ${PROJECT_ROOT_DIR}/htmlreport/cppcheck-htmlreport --file "$ERRORLIST_XML" --title "errorlist" --report-dir "$REPORT_DIR" # Check HTML syntax validate_html "$INDEX_HTML" validate_html "$STATS_HTML" -../cppcheck ../samples/memleak/good.c ../samples/resourceLeak/good.c --xml-version=2 --enable=information --suppressions-list=test_suppressions.txt --xml 2> "$UNMATCHEDSUPPR_XML" +${PROJECT_ROOT_DIR}/cppcheck ${PROJECT_ROOT_DIR}/samples/memleak/good.c ${PROJECT_ROOT_DIR}/samples/resourceLeak/good.c --xml-version=2 --enable=information --suppressions-list="${ABSOLUTE_SCRIPT_DIR}/test_suppressions.txt" --xml 2> "$UNMATCHEDSUPPR_XML" xmllint --noout "$UNMATCHEDSUPPR_XML" -$PYTHON cppcheck-htmlreport --file "$UNMATCHEDSUPPR_XML" --title "unmatched Suppressions" --report-dir="$REPORT_DIR" +$PYTHON ${PROJECT_ROOT_DIR}/htmlreport/cppcheck-htmlreport --file "$UNMATCHEDSUPPR_XML" --title "unmatched Suppressions" --report-dir="$REPORT_DIR" grep "unmatchedSuppression<.*>information<.*>Unmatched suppression: variableScope*<" "$INDEX_HTML" grep ">unmatchedSuppressioninformation<.*>Unmatched suppression: uninitstring<" "$INDEX_HTML" grep "notexisting" "$INDEX_HTML" diff --git a/htmlreport/example.cc b/test/tools/htmlreport/example.cc similarity index 100% rename from htmlreport/example.cc rename to test/tools/htmlreport/example.cc diff --git a/htmlreport/example.xml b/test/tools/htmlreport/example.xml similarity index 100% rename from htmlreport/example.xml rename to test/tools/htmlreport/example.xml diff --git a/htmlreport/test_htmlreport.py b/test/tools/htmlreport/test_htmlreport.py similarity index 86% rename from htmlreport/test_htmlreport.py rename to test/tools/htmlreport/test_htmlreport.py index 4fd6cf6c256..4b40650cf09 100755 --- a/htmlreport/test_htmlreport.py +++ b/test/tools/htmlreport/test_htmlreport.py @@ -14,11 +14,15 @@ else: import unittest -ROOT_DIR = os.path.split(os.path.abspath(os.path.dirname(__file__)))[0] +TEST_TOOLS_DIR = os.path.abspath(os.path.dirname(__file__)) +ROOT_DIR = os.path.split(os.path.dirname(os.path.dirname(TEST_TOOLS_DIR)))[0] +HTMLREPORT_DIR = os.path.join(ROOT_DIR, 'htmlreport') CPPCHECK_BIN = os.path.join(ROOT_DIR, 'cppcheck') -HTML_REPORT_BIN = os.path.join(os.path.abspath(os.path.dirname(__file__)), - 'cppcheck-htmlreport') +if os.getenv("PIP_PACKAGE_TEST") is not None: + HTML_REPORT_BIN = ['cppcheck-htmlreport'] +else: + HTML_REPORT_BIN = [sys.executable, os.path.join(HTMLREPORT_DIR, 'cppcheck-htmlreport')] class TestHTMLReport(unittest.TestCase): @@ -65,7 +69,7 @@ def checkReportNoError(self, xml_version): def testMissingInclude(self): with runCheck( - xml_filename=os.path.join(ROOT_DIR, 'htmlreport', 'example.xml'), + xml_filename=os.path.join(TEST_TOOLS_DIR, 'example.xml'), ) as (report, output_directory): self.assertIn(' Date: Thu, 9 May 2024 10:12:56 +0200 Subject: [PATCH 3/5] Fix #12718 restrict wrongly treated as keyword (#6390) --- lib/token.cpp | 36 +------------------------------- test/testincompletestatement.cpp | 6 +++--- test/testtokenize.cpp | 3 +++ 3 files changed, 7 insertions(+), 38 deletions(-) diff --git a/lib/token.cpp b/lib/token.cpp index 5e5f7226e45..44b09553605 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -100,38 +100,6 @@ static const std::unordered_set controlFlowKeywords = { "return" }; -// TODO: replace with Keywords::getX()? -// Another list of keywords -static const std::unordered_set baseKeywords = { - "asm", - "auto", - "break", - "case", - "const", - "continue", - "default", - "do", - "else", - "enum", - "extern", - "for", - "goto", - "if", - "inline", - "register", - "restrict", - "return", - "sizeof", - "static", - "struct", - "switch", - "typedef", - "union", - "volatile", - "while", - "void" -}; - void Token::update_property_info() { setFlag(fIsControlFlowKeyword, controlFlowKeywords.find(mStr) != controlFlowKeywords.end()); @@ -146,9 +114,7 @@ void Token::update_property_info() else if (std::isalpha((unsigned char)mStr[0]) || mStr[0] == '_' || mStr[0] == '$') { // Name if (mImpl->mVarId) tokType(eVariable); - else if (mTokensFrontBack.list.isKeyword(mStr)) - tokType(eKeyword); - else if (baseKeywords.count(mStr) > 0) + else if (mTokensFrontBack.list.isKeyword(mStr) || mStr == "asm") // TODO: not a keyword tokType(eKeyword); else if (mTokType != eVariable && mTokType != eFunction && mTokType != eType && mTokType != eKeyword) tokType(eName); diff --git a/test/testincompletestatement.cpp b/test/testincompletestatement.cpp index c3a65ed4b66..e70cffc1480 100644 --- a/test/testincompletestatement.cpp +++ b/test/testincompletestatement.cpp @@ -34,10 +34,10 @@ class TestIncompleteStatement : public TestFixture { const Settings settings = settingsBuilder().severity(Severity::warning).build(); #define check(...) check_(__FILE__, __LINE__, __VA_ARGS__) - void check_(const char* file, int line, const char code[], bool inconclusive = false) { + void check_(const char* file, int line, const char code[], bool inconclusive = false, bool cpp = true) { const Settings settings1 = settingsBuilder(settings).certainty(Certainty::inconclusive, inconclusive).build(); - std::vector files(1, "test.cpp"); + std::vector files(1, cpp ? "test.cpp" : "test.c"); Tokenizer tokenizer(settings1, *this); PreprocessorHelper::preprocess(code, files, tokenizer, *this); @@ -743,7 +743,7 @@ class TestIncompleteStatement : public TestFixture { check("void f() { char * const * a, * const * b; }", true); ASSERT_EQUALS("", errout_str()); - check("void f() { char * const * a = 0, * volatile restrict * b; }", true); + check("void f() { char * const * a = 0, * volatile restrict * b; }", true, /*cpp*/ false); ASSERT_EQUALS("", errout_str()); check("void f() { char * const * a = 0, * volatile const * b; }", true); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 13969de1430..5dacd24e065 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -7151,6 +7151,9 @@ class TestTokenizer : public TestFixture { ASSERT_NO_THROW(tokenizeAndStringify("typedef struct { typedef int T; } S;")); // #12700 + ASSERT_NO_THROW(tokenizeAndStringify("class A { bool restrict() const; };\n" + "bool A::restrict() const { return true; }")); // #12718 + ignore_errout(); } From 37dc79522b37398a77e0ac310d2264ca85add898 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 10 May 2024 10:20:27 +0200 Subject: [PATCH 4/5] Fix #12702 fuzzing crash in TemplateSimplifier::useDefaultArgumentValues (#6387) --- lib/tokenize.cpp | 2 ++ .../crash-adb20a108c3686d79bc9bd0e4025445e3a35fa49.crdownload | 1 + 2 files changed, 3 insertions(+) create mode 100644 test/cli/fuzz-crash/crash-adb20a108c3686d79bc9bd0e4025445e3a35fa49.crdownload diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index e529366f40c..113d68e8b66 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -8766,6 +8766,8 @@ void Tokenizer::findGarbageCode() const // Garbage templates.. if (isCPP()) { for (const Token *tok = tokens(); tok; tok = tok->next()) { + if (Token::simpleMatch(tok, "< >") && !(Token::Match(tok->tokAt(-1), "%name%") || (tok->tokAt(-1) && Token::Match(tok->tokAt(-2), "operator %op%")))) + syntaxError(tok); if (!Token::simpleMatch(tok, "template <")) continue; if (tok->previous() && !Token::Match(tok->previous(), ":|;|{|}|)|>|\"C++\"")) { diff --git a/test/cli/fuzz-crash/crash-adb20a108c3686d79bc9bd0e4025445e3a35fa49.crdownload b/test/cli/fuzz-crash/crash-adb20a108c3686d79bc9bd0e4025445e3a35fa49.crdownload new file mode 100644 index 00000000000..98e8746abd0 --- /dev/null +++ b/test/cli/fuzz-crash/crash-adb20a108c3686d79bc9bd0e4025445e3a35fa49.crdownload @@ -0,0 +1 @@ +template<#p<>tu< <>tu=e \ No newline at end of file From 1943b4dd7e64ae9c30501c82c2d0d6d42d5e4d52 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Sat, 11 May 2024 15:12:37 +0200 Subject: [PATCH 5/5] Deactivate failing scriptcheck using Python 3.5 (#6396) --- .github/workflows/scriptcheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scriptcheck.yml b/.github/workflows/scriptcheck.yml index 307310616bc..4103f3a3c08 100644 --- a/.github/workflows/scriptcheck.yml +++ b/.github/workflows/scriptcheck.yml @@ -47,7 +47,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - python-version: [3.5, 3.6, 3.7, 3.8, 3.9, '3.10', '3.11', '3.12'] + python-version: [3.6, 3.7, 3.8, 3.9, '3.10', '3.11', '3.12'] include: - python-version: '3.12' python-latest: true