From ac2ac0c705b108e451d3602e2c007215050f65fc Mon Sep 17 00:00:00 2001 From: Omar Chebib Date: Thu, 13 Oct 2022 13:28:10 +0800 Subject: [PATCH] CI: check_public_headers script will detect the use of static asserts in headers When a public header contains _Static_assert or static_assert, check_public_headers.py script will detect it and report it as an issue. Indeed, public headers shall now use ESP_STATIC_ASSERT. --- tools/ci/check_public_headers.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/tools/ci/check_public_headers.py b/tools/ci/check_public_headers.py index 5d1e69b109..1dd00d28f8 100644 --- a/tools/ci/check_public_headers.py +++ b/tools/ci/check_public_headers.py @@ -46,6 +46,11 @@ class HeaderFailedContainsCode(HeaderFailed): return 'Header Produced non-zero object' +class HeaderFailedContainsStaticAssert(HeaderFailed): + def __str__(self) -> str: + return 'Header uses _Static_assert or static_assert instead of ESP_STATIC_ASSERT' + + # Creates a temp file and returns both output as a string and a file name # def exec_cmd_to_temp_file(what: List, suffix: str='') -> Tuple[int, str, str, str, str]: @@ -74,6 +79,7 @@ class PublicHeaderChecker: PREPROC_OUT_SAME_HRD_FAILED = 5 # -> Both preprocessors produce the same, non-zero output (header file FAILs) PREPROC_OUT_DIFFERENT_WITH_EXT_C_HDR_OK = 6 # -> Both preprocessors produce different, non-zero output with extern "C" (header seems OK) PREPROC_OUT_DIFFERENT_NO_EXT_C_HDR_FAILED = 7 # -> Both preprocessors produce different, non-zero output without extern "C" (header fails) + HEADER_CONTAINS_STATIC_ASSERT = 8 # -> Header file contains _Static_assert instead of static_assert or ESP_STATIC_ASSERT def log(self, message: str, debug: bool=False) -> None: if self.verbose or debug: @@ -89,6 +95,9 @@ class PublicHeaderChecker: self.error_macro = re.compile(r'#error') self.error_orphan_kconfig = re.compile(r'#error CONFIG_VARS_USED_WHILE_SDKCONFIG_NOT_INCLUDED') self.kconfig_macro = re.compile(r'\bCONFIG_[A-Z0-9_]+') + self.static_assert = re.compile(r'(_Static_assert|static_assert)') + self.defines_assert = re.compile(r'#define[ \t]+ESP_STATIC_ASSERT') + self.auto_soc_header = re.compile(r'components/soc/esp[a-z0-9_]+/include(?:/rev[0-9]+)?/soc/[a-zA-Z0-9_]+.h') self.assembly_nocode = r'^\s*(\.file|\.text|\.ident|\.option|\.attribute).*$' self.check_threads: List[Thread] = [] @@ -160,6 +169,8 @@ class PublicHeaderChecker: return self.compile_one_header(header) elif res == self.PREPROC_OUT_SAME_HRD_FAILED: raise HeaderFailedCppGuardMissing() + elif res == self.HEADER_CONTAINS_STATIC_ASSERT: + raise HeaderFailedContainsStaticAssert() else: self.compile_one_header(header) temp_header = None @@ -187,12 +198,20 @@ class PublicHeaderChecker: def preprocess_one_header(self, header: str, num: int, ignore_sdkconfig_issue: bool=False) -> int: all_compilation_flags = ['-w', '-P', '-E', '-DESP_PLATFORM', '-include', header, self.main_c] + self.include_dir_flags + # just strip comments to check for CONFIG_... macros or static asserts + rc, out, err, _ = exec_cmd([self.gcc, '-fpreprocessed', '-dD', '-P', '-E', header] + self.include_dir_flags) if not ignore_sdkconfig_issue: - # just strip commnets to check for CONFIG_... macros - rc, out, err, _ = exec_cmd([self.gcc, '-fpreprocessed', '-dD', '-P', '-E', header] + self.include_dir_flags) if re.search(self.kconfig_macro, out): # enable defined #error if sdkconfig.h not included all_compilation_flags.append('-DIDF_CHECK_SDKCONFIG_INCLUDED') + # If the file contain _Static_assert or static_assert, make sure it does't not define ESP_STATIC_ASSERT and that it + # is not an automatically generated soc header file + grp = re.search(self.static_assert, out) + # Normalize the potential A//B, A/./B, A/../A, from the name + normalized_path = os.path.normpath(header) + if grp and not re.search(self.defines_assert, out) and not re.search(self.auto_soc_header, normalized_path): + self.log('{}: FAILED: contains {}. Please use ESP_STATIC_ASSERT'.format(header, grp.group(1)), True) + return self.HEADER_CONTAINS_STATIC_ASSERT try: # compile with C++, check for errors, outputs for a temp file rc, cpp_out, err, cpp_out_file, cmd = exec_cmd_to_temp_file([self.gpp, '--std=c++17'] + all_compilation_flags) @@ -317,6 +336,8 @@ def check_all_headers() -> None: * Check if the "#ifdef __cplusplus" header sentinels are present 4) "Header Produced non-zero object": Header contains some object, a definition * Check if no definition is present in the offending header file + 5) "Header contains _Static_assert or static_assert": Makes the use of _Static_assert or static_assert + functions instead of using ESP_STATIC_ASSERT macro Notes: * The script validates *all* header files (recursively) in public folders for all components.