skills/check-test-code-quality/rules/R013/SKILL.md
# R013: 注释的废弃代码 ## 规则信息 | 属性 | 值 | |------|-----| | 规则编号 | R013 | | 问题类型 | 注释的废弃代码 | | 严重级别 | Warning | | 规则复杂度 | complex | | 扫描范围 | 测试文件(`.test.ets`, `.test.ts`, `.test.js`) | | testcase字段 | 所属的it()名称,不在it()块内时为`-` | ## 问题描述 存在大量注释的废弃代码。测试文件中包含连续多行的注释代码块,这些代码已经不再使用但仍然保留在文件中,影响代码可读性。 ## 修复建议 直接删除注释的废弃代码。使用版本控制系统(如Git)保留历史记录,不需要在代码中注释保留。 ## 扫描逻辑 ### Step 1: 筛选测试文件 ```python import os TEST_EXTENSIONS = ('.test.ets', '.test.ts', '.test.js') def find_test_files(scan_root): test_files
npx skillsauth add openharmonyinsight/openharmony-skills skills/check-test-code-quality/rules/R013Install this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
| 属性 | 值 |
|------|-----|
| 规则编号 | R013 |
| 问题类型 | 注释的废弃代码 |
| 严重级别 | Warning |
| 规则复杂度 | complex |
| 扫描范围 | 测试文件(.test.ets, .test.ts, .test.js) |
| testcase字段 | 所属的it()名称,不在it()块内时为- |
存在大量注释的废弃代码。测试文件中包含连续多行的注释代码块,这些代码已经不再使用但仍然保留在文件中,影响代码可读性。
直接删除注释的废弃代码。使用版本控制系统(如Git)保留历史记录,不需要在代码中注释保留。
import os
TEST_EXTENSIONS = ('.test.ets', '.test.ts', '.test.js')
def find_test_files(scan_root):
test_files = []
for dirpath, dirnames, filenames in os.walk(scan_root):
for fn in filenames:
if fn.endswith(TEST_EXTENSIONS):
test_files.append(os.path.join(dirpath, fn))
return test_files
检测连续3行及以上的注释行组成的代码块。
import re
def find_comment_blocks(content):
lines = content.split('\n')
blocks = []
current_block = []
for i, line in enumerate(lines, 1):
stripped = line.strip()
is_comment = (
stripped.startswith('//') or
stripped.startswith('*') or
stripped.startswith('/*') or
(current_block and stripped.startswith('*/'))
)
if is_comment:
current_block.append((i, line))
else:
if len(current_block) >= 3:
blocks.append(list(current_block))
current_block = []
if len(current_block) >= 3:
blocks.append(list(current_block))
return blocks
判断注释块内容是否包含代码特征(而非普通文档注释)。
CODE_PATTERNS = [
r'\bfunction\b',
r'\bvar\b',
r'\blet\b',
r'\bconst\b',
r'\breturn\b',
r'\bif\s*\(',
r'\bfor\s*\(',
r'\bwhile\s*\(',
r'\bswitch\s*\(',
r'\bcase\b',
r'\bbreak\b',
r'\bclass\b',
r'\bimport\b',
r'\bexport\b',
r'\basync\b',
r'\bawait\b',
r'\btry\b',
r'\bcatch\b',
r'\bthrow\b',
r'\bnew\b',
r'\bthis\b',
r'\bexpect\b',
r'\bit\s*\(',
r'\bdescribe\s*\(',
r'\{',
r'\}',
r';',
r'\=\>',
r'\.\w+\s*\(',
]
def extract_comment_text(block):
texts = []
for _, line in block:
stripped = line.strip()
if stripped.startswith('//'):
texts.append(stripped[2:].strip())
elif stripped.startswith('*') and not stripped.startswith('*/'):
texts.append(stripped[1:].strip())
elif stripped.startswith('/*'):
texts.append(stripped[2:].strip())
elif stripped.startswith('*/'):
texts.append(stripped[2:].strip())
else:
texts.append(stripped)
return '\n'.join(texts)
def has_code_characteristics(comment_text):
pattern_count = 0
for pattern in CODE_PATTERNS:
if re.search(pattern, comment_text):
pattern_count += 1
return pattern_count >= 2
检查注释块中是否包含完整的函数定义或测试用例声明。
def has_complete_function(comment_text):
patterns = [
r'function\s+\w+\s*\([^)]*\)\s*\{',
r'(?:async\s+)?\w+\s*=\s*(?:async\s+)?\([^)]*\)\s*(?:=>|\{)',
r'it\s*\(\s*["\'][^"\']+["\']',
r'describe\s*\(\s*["\'][^"\']+["\']',
r'\bclass\s+\w+',
]
match_count = sum(1 for p in patterns if re.search(p, comment_text))
return match_count >= 1
def is_javadoc_like(comment_text):
javadoc_markers = [
r'@tc\.name',
r'@tc\.number',
r'@tc\.desc',
r'@tc\.size',
r'@tc\.type',
r'@tc\.level',
r'@param',
r'@return',
r'@throws',
r'@since',
r'@deprecated',
]
match_count = sum(1 for m in javadoc_markers if re.search(m, comment_text))
return match_count >= 2
解析文件中所有it()块的范围,判断注释块的起始行落在哪个it()块内。
def find_it_blocks(content):
it_pattern = re.compile(
r"it\s*\(\s*['\"]([^'\"]+)['\"]",
re.MULTILINE
)
it_blocks = []
for match in it_pattern.finditer(content):
name = match.group(1)
start_line = content[:match.start()].count('\n') + 1
it_blocks.append((start_line, name))
return sorted(it_blocks, key=lambda x: x[0])
def get_testcase_for_line(line_num, it_blocks):
testcase = '-'
for i, (start, name) in enumerate(it_blocks):
if i + 1 < len(it_blocks):
next_start = it_blocks[i + 1][0]
if start < line_num < next_start:
testcase = name
break
else:
if line_num > start:
testcase = name
break
return testcase
def scan_r013(scan_root, base_dir):
issues = []
test_files = find_test_files(scan_root)
for file_path in test_files:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
it_blocks = find_it_blocks(content)
comment_blocks = find_comment_blocks(content)
for block in comment_blocks:
start_line = block[0][0]
end_line = block[-1][0]
comment_text = extract_comment_text(block)
if is_javadoc_like(comment_text):
continue
if not has_code_characteristics(comment_text):
continue
is_function = has_complete_function(comment_text)
if not is_function and len(block) < 5:
continue
rel_path = os.path.relpath(file_path, base_dir)
testcase = get_testcase_for_line(start_line, it_blocks)
block_preview = '\n'.join(line for _, line in block[:5])
if len(block) > 5:
block_preview += '\n ... (省略' + str(len(block) - 5) + '行)'
issues.append({
'rule': 'R013',
'type': '注释的废弃代码',
'severity': 'Warning',
'file': rel_path,
'line': start_line,
'testcase': testcase,
'snippet': block_preview,
'suggestion': (
f'第{start_line}-{end_line}行存在注释的废弃代码(共{len(block)}行)。'
f'建议直接删除,使用版本控制系统保留历史记录。'
),
})
return issues
// 错误1:大量注释的废弃代码
// 废弃的旧方法 - 不要删除,保留参考
// function oldMethod() {
// let value = testFunction();
// expect(value).assertEqual('expected');
// return value;
// }
function newMethod() {
let newValue = newTestFunction();
expect(newValue).assertEqual('newExpected');
}
// 错误2:注释掉的完整测试用例
it('test001', () => {
// 废弃的测试逻辑
// let value = testFunction();
// expect(value).assertEqual('expected');
// done();
let newValue = newTestFunction();
expect(newValue).assertEqual('newExpected');
});
// 错误3:注释掉的函数定义(3行以上)
// function oldTestMethod(done: Function) {
// console.info('old test start');
// let result = doSomething();
// expect(result).assertTrue();
// done();
// }
// 正确:直接删除废弃代码,保持代码简洁
it('test001', () => {
let newValue = newTestFunction();
expect(newValue).assertEqual('newExpected');
});
// 正确:如果需要保留旧逻辑作为参考,使用Git历史记录
function newMethod() {
let currentValue = currentFunction();
expect(currentValue).assertEqual('expected');
}
以下注释块不应被报告:
@tc.name、@tc.number、@param、@return等标记的注释// let x = 1;一行,不构成"废弃代码块"每条issue的字段:
| 字段 | 值 |
|------|-----|
| rule | R013 |
| type | 注释的废弃代码 |
| severity | Warning |
| file | 相对路径(如xxx/test.test.ets) |
| line | 注释块起始行号 |
| testcase | 所属的it()名称,不在it()块内时为- |
| snippet | 注释块前5行预览 |
| suggestion | 第X-Y行存在注释的废弃代码(共N行)。建议直接删除,使用版本控制系统保留历史记录。 |
testing
--- name: ohos-req-value-decision description: Use after review meeting to record decision and route to next step. Triggers: 评审决策纪要, 评审结论回流, value decision, 评审接纳, 评审不接纳, 评审退回, 下次重新上会. Do NOT use for feature baseline (ohos-req-feature-baseline), review gate checks (ohos-req-review-gate), or IR generation (ohos-req-feature-to-ir). metadata: author: openharmony scope: common stage: requirements capability: value-decision version: 0.3.0 status: draft tags: - sdd - requirements
development
Use when converting an OpenHarmony requirement document, spec, or design proposal into an OpenHarmony review slide deck (需求评审 / 需求变更评审 / 设计评审 PPTX) — produces the fixed OpenHarmony-branded review-deck structure (OH logo on every page) with architecture/flow diagrams and field tables. Triggers on "需求评审PPT", "需求变更评审", "把需求文档转成评审PPT", "spec转评审PPT", "requirement/spec to review deck". NOT for arbitrary or generic slide decks unrelated to OpenHarmony requirement/design review.
testing
Use when performing the Phase 0 Step 0.5 Review Ready Gate on a 04-feature.md, especially when the user says "evaluate gate", "review readiness", "feature ready?", "should we generate IR", or when the ohos-req-intake-orchestration main session needs a structured Ready / Conditional Ready / Not Ready judgment instead of doing the check inline. Reads 01-04, runs seven fixed checks plus a conditional-items check, and returns a machine-readable JSON summary plus a human-readable table that the main session can route on. Do NOT use for feature baseline generation (ohos-req-feature-baseline), value decision recording (ohos-req-value-decision), or IR generation (ohos-req-feature-to-ir).
testing
--- name: ohos-req-requirement-intake description: Use when importing an OHOS requirement into Phase 0.1, especially for 01-requirement.md, requirement intake, background, user value, scenarios, scope, FR/NFR, affected modules, or priority. Triggers: 需求导入, 01-requirement, 需求基线, RR单号. Do NOT use for feasibility analysis (ohos-req-feasibility-analysis), architecture decision (ohos-req-arch-decision), or feature baseline (ohos-req-feature-baseline). metadata: author: openharmony scope: common