From 6008275aae676a4d8d018220eb1436a3f6f58daa Mon Sep 17 00:00:00 2001 From: Valerii Koval Date: Wed, 29 Sep 2021 14:46:02 +0300 Subject: [PATCH] Properly handle in-progress C++ standards when invoking Cppcheck // Resolve #3944 (#4070) --- HISTORY.rst | 1 + platformio/commands/check/tools/cppcheck.py | 24 ++++++++-- tests/commands/test_check.py | 53 ++++++++++++++++++--- 3 files changed, 67 insertions(+), 11 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index c4371ce5..a2bfc732 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -14,6 +14,7 @@ PlatformIO Core 5 - Allowed to override a default library builder via a new ``builder`` field in a ``build`` group of `library.json `__ manifest (`issue #3957 `_) - Fixed a "KeyError: Invalid board option 'build.cpu'" when using a precompiled library with a board that does not have a CPU field in the manifest (`issue #4056 `_) - Fixed a "FileExist" error when the `platformio ci `__ command is used in pair with the ``--keep-build-dir`` option (`issue #4011 `_) +- Fixed an issue with draft values of C++ language standards that broke static analysis via Cppcheck (`issue #3944 `_) 5.2.0 (2021-09-13) ~~~~~~~~~~~~~~~~~~ diff --git a/platformio/commands/check/tools/cppcheck.py b/platformio/commands/check/tools/cppcheck.py index 8dd6041a..bc06799a 100644 --- a/platformio/commands/check/tools/cppcheck.py +++ b/platformio/commands/check/tools/cppcheck.py @@ -141,10 +141,11 @@ class CppcheckCheckTool(CheckToolBase): build_flags = self.cxx_flags if language == "c++" else self.cc_flags - for flag in build_flags: - if "-std" in flag: - # Standards with GNU extensions are not allowed - cmd.append("-" + flag.replace("gnu", "c")) + if not self.is_flag_set("--std", flags): + # Try to guess the standard version from the build flags + for flag in build_flags: + if "-std" in flag: + cmd.append("-" + self.convert_language_standard(flag)) cmd.extend( ["-D%s" % d for d in self.cpp_defines + self.toolchain_defines[language]] @@ -224,6 +225,21 @@ class CppcheckCheckTool(CheckToolBase): # Cppcheck is configured to return '3' if a defect is found return cmd_result["returncode"] in (0, 3) + @staticmethod + def convert_language_standard(flag): + cpp_standards_map = { + "0x": "11", + "1y": "14", + "1z": "17", + "2a": "20", + } + + standard = flag[-2:] + # Note: GNU extensions are not supported and converted to regular standards + return flag.replace("gnu", "c").replace( + standard, cpp_standards_map.get(standard, standard) + ) + def check(self, on_defect_callback=None): self._on_defect_callback = on_defect_callback diff --git a/tests/commands/test_check.py b/tests/commands/test_check.py index 98400c17..d4b3b79b 100644 --- a/tests/commands/test_check.py +++ b/tests/commands/test_check.py @@ -15,7 +15,6 @@ # pylint: disable=redefined-outer-name import json -import sys from os.path import isfile, join import pytest @@ -132,6 +131,47 @@ def test_check_language_standard_definition_passed(clirunner, tmpdir): assert "--std=c++17" in result.output +def test_check_language_standard_option_is_converted(clirunner, tmpdir): + config = ( + DEFAULT_CONFIG + + """ +build_flags = -std=gnu++1y + """ + ) + tmpdir.join("platformio.ini").write(config) + tmpdir.mkdir("src").join("main.cpp").write(TEST_CODE) + result = clirunner.invoke(cmd_check, ["--project-dir", str(tmpdir), "-v"]) + + assert "--std=c++14" in result.output + + +def test_check_language_standard_is_prioritized_over_build_flags(clirunner, tmpdir): + config = ( + DEFAULT_CONFIG + + """ +check_flags = --std=c++03 +build_flags = -std=c++17 + """ + ) + tmpdir.join("platformio.ini").write(config) + tmpdir.mkdir("src").join("main.cpp").write(TEST_CODE) + result = clirunner.invoke(cmd_check, ["--project-dir", str(tmpdir), "-v"]) + + assert "--std=c++03" in result.output + assert "--std=c++17" not in result.output + + +def test_check_language_standard_for_c_language(clirunner, tmpdir): + config = DEFAULT_CONFIG + "\nbuild_flags = -std=c11" + tmpdir.join("platformio.ini").write(config) + tmpdir.mkdir("src").join("main.c").write(TEST_CODE) + result = clirunner.invoke(cmd_check, ["--project-dir", str(tmpdir), "-v"]) + + assert "--std=c11" in result.output + assert "__STDC_VERSION__=201112L" in result.output + assert "__cplusplus" not in result.output + + def test_check_severity_threshold(clirunner, validate_cliresult, check_dir): result = clirunner.invoke( cmd_check, ["--project-dir", str(check_dir), "--severity=high"] @@ -451,12 +491,11 @@ int main() { """ ) - frameworks = ["arduino", "stm32cube"] - if sys.version_info[0] == 3: - # Zephyr only supports Python 3 - frameworks.append("zephyr") - - for framework in frameworks: + for framework in ( + "arduino", + "stm32cube", + "zephyr", + ): for tool in ("cppcheck", "clangtidy", "pvs-studio"): tmpdir.join("platformio.ini").write(config % (framework, tool)) result = clirunner.invoke(cmd_check, ["--project-dir", str(tmpdir)])