1# 2# Copyright (c) 2006-2023, RT-Thread Development Team 3# 4# SPDX-License-Identifier: Apache-2.0 5# 6# Change Logs: 7# Date Author Notes 8# 2023-05-16 dejavudwh the first version 9# 2024-09-12 supperthomas add cppcheck summary for detail 10# 11 12import click 13import logging 14import subprocess 15import sys 16import format_ignore 17import os 18''' 19--suppress=syntaxError: 20该选项用于抑制特定的错误类型。在这里,syntaxError 是被忽略的错误类型。这意味着 Cppcheck 不会报告语法错误(syntaxError)。这是因为在某些情况下,分析工具可能会误报语法错误,但 CI(持续集成)系统会在编译时捕获这些错误,因此可以忽略。 21 22--enable=warning: 23该选项用于启用特定类型的检查。Cppcheck 可以检查不同的级别和种类的问题,如错误、警告、性能问题等。--enable=warning 启用的是警告级别的检查,帮助检测代码中可能存在的问题,但不是严重的错误。 24 25performance: 26Cppcheck 可以启用多个检查种类,在这里指定了 performance,意味着会检查与代码性能相关的潜在问题,例如不必要的拷贝操作、无效的条件判断等。这有助于提高代码的运行效率。 27 28portability: 29Cppcheck 会检查代码的可移植性问题。可移植性检查帮助发现代码在不同平台或编译器中可能遇到的问题,如特定平台上不支持的类型、函数或特性。这对跨平台开发非常重要。 30 31--inline-suppr: 32该选项允许在代码中使用注释来抑制特定的警告或错误信息。通过这种方式,开发者可以直接在代码中添加注释,告诉 Cppcheck 忽略某些检查或警告。例如,开发者可以在代码中添加 // cppcheck-suppress <message> 来抑制特定的警告信息。 33 34--error-exitcode=1: 35该选项告诉 Cppcheck 如果遇到错误,就返回指定的退出码。在这里指定的是 1。这对自动化工具非常有用,尤其是在 CI 环境中,因为它可以通过检查返回码来判断 Cppcheck 是否发现了错误。如果有错误,CI 系统会将整个任务标记为失败。 36 37--force: 38这个选项强制 Cppcheck 对所有文件进行检查,即使它检测到编译条件缺失或某些配置问题。通常,如果某些宏定义或依赖项缺失,Cppcheck 可能会跳过某些文件的检查。但 --force 会强制工具继续执行分析,即使有可能缺少某些信息。这在某些大型项目中很有用,可以确保所有文件都经过检查。 39''' 40def add_summary(text): 41 """ 42 add summary to github action. 43 """ 44 os.system(f'echo "{text}" >> $GITHUB_STEP_SUMMARY ;') 45 46class CPPCheck: 47 def __init__(self, file_list): 48 self.file_list = file_list 49 50 def check(self): 51 file_list_filtered = [file for file in self.file_list if file.endswith(('.c', '.cpp', '.cc', '.cxx'))] 52 logging.info("Start to static code analysis.") 53 check_result = True 54 for file in file_list_filtered: 55 macros = [] 56 if os.path.basename(file) == 'lwp.c': 57 macros.append('-DRT_USING_DFS') 58 59 result = subprocess.run( 60 [ 61 'cppcheck', 62 '-DRT_ASSERT(x)=', 63 '-DRTM_EXPORT(x)=', 64 '-Drt_list_for_each_entry(a,b,c)=a=(void*)b;', 65 '-I include', 66 '-I thread/components/finsh', 67 # it's okay because CI will do the real compilation to check this 68 '--suppress=syntaxError', 69 '--check-level=exhaustive', 70 '--enable=warning', 71 'performance', 72 'portability', 73 '--inline-suppr', 74 '--error-exitcode=1', 75 '--force', 76 file 77 ] + macros, 78 stdout = subprocess.PIPE, stderr = subprocess.PIPE) 79 logging.info(result.stdout.decode()) 80 logging.info(result.stderr.decode()) 81 if result.stderr: 82 add_summary("The following errors are for reference only. If they are not actual issues, please ignore them and do not make unnecessary modifications.") 83 add_summary("以下错误仅供参考,如果发现没有问题,请直接忽略,不需要强行修改") 84 add_summary(f"- :rotating_light: {result.stderr.decode()}") 85 check_result = False 86 return check_result 87 88@click.group() 89@click.pass_context 90def cli(ctx): 91 pass 92 93@cli.command() 94def check(): 95 """ 96 static code analysis(cppcheck). 97 """ 98 format_ignore.init_logger() 99 # get modified files list 100 checkout = format_ignore.CheckOut() 101 file_list = checkout.get_new_file() 102 if file_list is None: 103 logging.error("checkout files fail") 104 sys.exit(1) 105 106 # use cppcheck 107 cpp_check = CPPCheck(file_list) 108 cpp_check_result = cpp_check.check() 109 110 if not cpp_check_result: 111 logging.error("static code analysis(cppcheck) fail.") 112 sys.exit(1) 113 logging.info("check success.") 114 sys.exit(0) 115 116 117if __name__ == '__main__': 118 cli() 119