Skip to content
202 changes: 202 additions & 0 deletions addons/custom.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
自定义静态检查框架 (Custom Static Check Framework)

这是一个与 Cppcheck addons 高度兼容的可扩展自定义静态检查框架。
基于 cppcheck.py 的 checker 注册机制,支持模块化规则开发。

使用示例:
cppcheck --dump main.cpp
python custom.py --enable=all main.cpp.dump
python custom.py --enable=metrics,flow --max-cyclomatic=15 main.cpp.dump
"""

import cppcheckdata
import sys
import os
import argparse

# 导入自定义规则模块
# 规则模块应放在 custom_rules 目录下
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'custom_rules'))

# 全局变量:addon 名称(强制为 'custom')
ADDON_NAME = 'custom'

# 全局变量:已注册的 checker 列表
__checkers__ = []

# 全局变量:当前错误 ID
__errorid__ = ''

# 全局变量:配置参数
__config__ = {
'max_cyclomatic': 10, # 圈复杂度默认阈值
'enabled_rules': set(), # 启用的规则集合
}


def checker(f):
"""
装饰器:注册一个 checker 函数

用法:
@custom.checker
def my_rule(cfg, data):
# 检查逻辑
pass

Args:
f: checker 函数,签名应为 (cfg, data)
- cfg: Configuration 对象
- data: CppcheckData 对象

Returns:
原函数
"""
__checkers__.append(f)
return f


def reportError(location, severity, message, errorId=None):
"""
报告错误(通过 cppcheckdata.reportError)

Args:
location: Location 对象或 Token 对象
severity: 严重级别 ('error', 'warning', 'style', 'performance', 'portability', 'information')
message: 错误消息
errorId: 错误 ID(可选,默认使用当前 checker 函数名)
"""
cppcheckdata.reportError(location, severity, message, ADDON_NAME, errorId or __errorid__)


def parse_arguments():
"""
解析命令行参数

Returns:
Namespace: 解析后的参数对象
"""
parser = argparse.ArgumentParser(description='自定义静态检查框架')

# 继承 cppcheckdata.ArgumentParser 的参数
parser.add_argument('dumpfile', nargs='+', help='Cppcheck dump 文件路径')
parser.add_argument('--cli', action='store_true', help='CLI 模式(JSON 输出)')
parser.add_argument('-q', '--quiet', action='store_true', help='安静模式')

# 自定义参数
parser.add_argument('--enable', type=str, default='all',
help='启用的规则(逗号分隔),默认: all。'
'可选值: all, metrics, flow, 或其组合')
parser.add_argument('--max-cyclomatic', type=int, default=10,
help='圈复杂度最大阈值,默认: 10')

# 兼容性参数(供可能的未来扩展)
parser.add_argument('--verify', action='store_true', help='验证模式(预留)')

args = parser.parse_args()

return args


def load_rules(enabled_rules):
"""
根据启用的规则列表动态加载规则模块

Args:
enabled_rules: set,启用的规则名称集合
"""
# 如果启用 'all',则加载所有规则
if 'all' in enabled_rules:
enabled_rules = {'metrics', 'flow'}

# 导入并注册规则
if 'metrics' in enabled_rules:
try:
import metrics
if not __config__['quiet']:
sys.stderr.write('Loaded rule: metrics (cyclomatic complexity check)\n')
except ImportError as e:
sys.stderr.write(f'Warning: Failed to load metrics rule: {e}\n')
except Exception as e:
sys.stderr.write(f'Error loading metrics rule: {e}\n')
import traceback
traceback.print_exc()

if 'flow' in enabled_rules:
try:
import flow
if not __config__['quiet']:
sys.stderr.write('Loaded rule: flow (return path check)\n')
except ImportError as e:
sys.stderr.write(f'Warning: Failed to load flow rule: {e}\n')
except Exception as e:
sys.stderr.write(f'Error loading flow rule: {e}\n')
import traceback
traceback.print_exc()



def run_checkers():
"""
主执行函数:解析参数、加载规则、执行检查
"""
global __errorid__

# 解析参数
args = parse_arguments()

# 更新配置
__config__['max_cyclomatic'] = args.max_cyclomatic
__config__['quiet'] = args.quiet

# 解析 --enable 参数
enabled_rules = set(r.strip() for r in args.enable.split(','))
__config__['enabled_rules'] = enabled_rules

# 加载规则
load_rules(enabled_rules)

# 如果没有 checker,退出
if len(__checkers__) == 0:
if not args.quiet:
sys.stderr.write('Warning: No checkers loaded\n')
return

# 遍历所有 dump 文件
for dumpfile in args.dumpfile:
if not args.quiet:
sys.stderr.write(f'Checking {dumpfile}...\n')

# 解析 dump 文件
try:
data = cppcheckdata.CppcheckData(dumpfile)
except Exception as e:
sys.stderr.write(f'Error: Failed to parse {dumpfile}: {e}\n')
continue

# 遍历所有配置
for cfg in data.iterconfigurations():
if not args.quiet:
sys.stderr.write(f'Checking {dumpfile}, config {cfg.name}...\n')

# 执行所有 checker
for c in __checkers__:
__errorid__ = c.__name__
try:
c(cfg, data)
except Exception as e:
sys.stderr.write(f'Error in checker {c.__name__}: {e}\n')
import traceback
traceback.print_exc()


# 导出公共接口
__all__ = ['checker', 'reportError', 'run_checkers', '__config__']


if __name__ == '__main__':
run_checkers()
sys.exit(cppcheckdata.EXIT_CODE)
8 changes: 8 additions & 0 deletions addons/custom_rules/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""
自定义规则包 (Custom Rules Package)

这个包包含所有自定义静态检查规则。
每个规则模块应使用 @custom.checker 装饰器注册检查函数。
"""

__all__ = ['metrics', 'flow']
Loading