Skip to content

18.2 代码审查技能

代码审查技能概述

代码审查技能是 Claude Code Skills 中用于自动化代码审查的重要工具。它可以帮助开发者快速识别代码中的问题,提高代码质量和可维护性。

python
## 审查类型

### 1\. 静态代码分析

#### 1.1 代码质量检查

    python


    # src/skills/code_reviewer.py
    from typing import Dict, Any, List
    from claude_code_sdk import Skill, SkillContext, SkillResult
    import re

    class CodeReviewerSkill(Skill):
        """代码审查技能"""

        def __init__(self):
            super().__init__(
                name="code-reviewer",
                version="1.0.0",
                description="Automated code review skill"
            )

            # 定义审查规则
            self.rules = {
                "naming": self.check_naming_conventions,
                "complexity": self.check_complexity,
                "security": self.check_security,
                "performance": self.check_performance,
                "documentation": self.check_documentation
            }

        def get_parameters_schema(self) -> Dict[str, Any]:
            return {
                "type": "object",
                "properties": {
                    "file_path": {
                        "type": "string",
                        "description": "Path to the file to review"
                    },
                    "code": {
                        "type": "string",
                        "description": "Code to review (alternative to file_path)"
                    },
                    "language": {
                        "type": "string",
                        "enum": ["python", "javascript", "java", "go"],
                        "description": "Programming language"
                    },
                    "rules": {
                        "type": "array",
                        "description": "Rules to apply",
                        "items": {
                            "type": "string",
                            "enum": ["naming", "complexity", "security", "performance", "documentation"]
                        }
                    },
                    "severity": {
                        "type": "string",
                        "enum": ["all", "error", "warning", "info"],
                        "description": "Minimum severity level"
                    }
                },
                "required": ["language"]
            }

        def execute(self, parameters: Dict[str, Any], context: SkillContext) -> SkillResult:
            try:
                language = parameters["language"]
                rules_to_apply = parameters.get("rules", list(self.rules.keys()))
                severity = parameters.get("severity", "all")

                # 获取代码
                if "file_path" in parameters:
                    code = context.read_file(parameters["file_path"])
                    file_path = parameters["file_path"]
                elif "code" in parameters:
                    code = parameters["code"]
                    file_path = "<inline>"
                else:
                    return SkillResult(
                        success=False,
                        error="Either file_path or code must be provided"
                    )

                # 执行审查
                issues = []
                for rule_name in rules_to_apply:
                    if rule_name in self.rules:
                        rule_func = self.rules[rule_name]
                        rule_issues = rule_func(code, language)
                        issues.extend(rule_issues)

                # 过滤严重性
                if severity != "all":
                    severity_levels = {"error": 3, "warning": 2, "info": 1}
                    min_level = severity_levels.get(severity, 0)
                    issues = [
                        issue for issue in issues
                        if severity_levels.get(issue["severity"], 0) >= min_level
                    ]

                # 生成报告
                report = self.generate_report(code, issues, file_path)

                return SkillResult(
                    success=True,
                    data={
                        "file_path": file_path,
                        "language": language,
                        "rules_applied": rules_to_apply,
                        "issues": issues,
                        "issue_count": len(issues),
                        "report": report
                    }
                )
            except Exception as e:
                return SkillResult(
                    success=False,
                    error=str(e)
                )

        def check_naming_conventions(self, code: str, language: str) -> List[Dict]:
            """检查命名规范"""
            issues = []

            if language == "python":
                # 检查函数名(应该是 snake_case)
                func_pattern = r'def\s+([A-Z][a-zA-Z0-9_]*)\s*\('
                for match in re.finditer(func_pattern, code):
                    line_num = code[:match.start()].count('\n') + 1
                    issues.append({
                        "type": "naming",
                        "severity": "warning",
                        "line": line_num,
                        "message": f"Function name '{match.group(1)}' should use snake_case",
                        "suggestion": match.group(1).lower()
                    })

                # 检查类名(应该是 CamelCase)
                class_pattern = r'class\s+([a-z][a-zA-Z0-9_]*)\s*[:\(]'
                for match in re.finditer(class_pattern, code):
                    line_num = code[:match.start()].count('\n') + 1
                    issues.append({
                        "type": "naming",
                        "severity": "warning",
                        "line": line_num,
                        "message": f"Class name '{match.group(1)}' should use CamelCase",
                        "suggestion": match.group(1).title()
                    })

            elif language == "javascript":
                # 检查常量(应该是 UPPER_CASE)
                const_pattern = r'const\s+([a-z][a-zA-Z0-9_]*)\s*='
                for match in re.finditer(const_pattern, code):
                    line_num = code[:match.start()].count('\n') + 1
                    issues.append({
                        "type": "naming",
                        "severity": "info",
                        "line": line_num,
                        "message": f"Constant '{match.group(1)}' should use UPPER_CASE",
                        "suggestion": match.group(1).upper()
                    })

            return issues

        def check_complexity(self, code: str, language: str) -> List[Dict]:
            """检查复杂度"""
            issues = []
            lines = code.split('\n')

            for i, line in enumerate(lines, 1):
                # 计算缩进级别
                indent = len(line) - len(line.lstrip())

                # 检查过深的嵌套
                if indent > 24:
                    issues.append({
                        "type": "complexity",
                        "severity": "warning",
                        "line": i,
                        "message": f"Deep nesting detected (indent level: {indent // 4})",
                        "suggestion": "Consider refactoring to reduce nesting"
                    })

                # 检查长行
                if len(line) > 120:
                    issues.append({
                        "type": "complexity",
                        "severity": "info",
                        "line": i,
                        "message": f"Line too long ({len(line)} characters)",
                        "suggestion": "Break the line into multiple lines"
                    })

            return issues

    ```python

    def check_security(self, code: str, language: str) -> List[Dict]:
        """检查安全问题"""
        issues = []

```python
        if language == "python":
            # 检查 eval 使用
            eval_pattern = r'\beval\s*\('
            for match in re.finditer(eval_pattern, code):
                line_num = code[:match.start()].count('\n') + 1
                issues.append({
                    "type": "security",
                    "severity": "error",
                    "line": line_num,
                    "message": "Use of eval() is dangerous",
                    "suggestion": "Use ast.literal_eval() or alternative safe methods"
                })

            # 检查 exec 使用
            exec_pattern = r'\bexec\s*\('
            for match in re.finditer(exec_pattern, code):
                line_num = code[:match.start()].count('\n') + 1
                issues.append({
                    "type": "security",
                    "severity": "error",
                    "line": line_num,
                    "message": "Use of exec() is dangerous",
                    "suggestion": "Avoid using exec() for security reasons"
                })

            # 检查硬编码密码
            password_pattern = r'(password|passwd|pwd)\s*=\s*["\'][^"\']+["\']'
            for match in re.finditer(password_pattern, code, re.IGNORECASE):
                line_num = code[:match.start()].count('\n') + 1
                issues.append({
                    "type": "security",
                    "severity": "warning",
                    "line": line_num,
                    "message": "Hardcoded password detected",
                    "suggestion": "Use environment variables or configuration files"
                })

        elif language == "javascript":
            # 检查 innerHTML 使用
            innerhtml_pattern = r'\.innerHTML\s*='
            for match in re.finditer(innerhtml_pattern, code):
                line_num = code[:match.start()].count('\n') + 1
                issues.append({
                    "type": "security",
                    "severity": "warning",
                    "line": line_num,
                    "message": "Use of innerHTML can lead to XSS vulnerabilities",
                    "suggestion": "Use textContent or sanitize input"
                })

        return issues

    def check_performance(self, code: str, language: str) -> List[Dict]:
        """检查性能问题"""
        issues = []

        if language == "python":
            # 检查循环中的字符串拼接
            lines = code.split('\n')
            in_loop = False
            loop_indent = 0

            for i, line in enumerate(lines, 1):
                # 检测循环
                if re.match(r'\s*(for|while)\s+', line):
                    in_loop = True
                    loop_indent = len(line) - len(line.lstrip())
                elif in_loop and len(line) - len(line.lstrip()) <= loop_indent:
                    in_loop = False

                # 检查字符串拼接
                if in_loop and '+=' in line and '"' in line and "'" in line:
                    issues.append({
                        "type": "performance",
                        "severity": "warning",
                        "line": i,
                        "message": "String concatenation in loop may be inefficient",
                        "suggestion": "Use list and join() for better performance"
                    })

        return issues

    def check_documentation(self, code: str, language: str) -> List[Dict]:
        """检查文档"""
        issues = []

        if language == "python":
            # 检查函数是否有文档字符串
            func_pattern = r'def\s+(\w+)\s*\([^)]*\):'
            for match in re.finditer(func_pattern, code):
                func_name = match.group(1)
                func_start = match.end()

# 检查下一行是否有文档字符串

remaining_code = code[func_start:func_start + 100] if not re.search(r'\s*"""', remaining_code): line_num = code[:match.start()].count('\n') + 1 issues.append({ "type": "documentation", "severity": "info", "line": line_num, "message": f"Function '{func_name}' lacks docstring", "suggestion": "Add a docstring to describe the function" })
return issues

def generate_report(self, code: str, issues: List[Dict], file_path: str) -> str: """生成审查报告""" report = f"# Code Review Report for {file_path}\n\n"

# 统计

error_count = sum(1 for i in issues if i["severity"] == "error") warning_count = sum(1 for i in issues if i["severity"] == "warning") info_count = sum(1 for i in issues if i["severity"] == "info")

report += f"## Summary\n\n" report += f"- Total Issues: {len(issues)}\n" report += f"- Errors: {error_count}\n" report += f"- Warnings: {warning_count}\n" report += f"- Info: {info_count}\n\n"

# 按类型分组

issues_by_type = {} for issue in issues: issue_type = issue["type"] if issue_type not in issues_by_type: issues_by_type[issue_type] = [] issues_by_type[issue_type].append(issue)

# 详细问题

for issue_type, type_issues in issues_by_type.items(): report += f"## {issue_type.title()} Issues ({len(type_issues)})\n\n"

for issue in type_issues: severity_icon = { "error": "❌", "warning": "⚠️", "info": "ℹ️" }.get(issue["severity"], "•")

report += f"{severity_icon} **Line {issue['line']}** : {issue['message']}\n" if "suggestion" in issue: report += f" 💡 Suggestion: {issue['suggestion']}\n" report += "\n"

return report

### 2\. 代码风格检查

#### 2.1 PEP 8 检查

    bash


    python

    # src/skills/pep8_checker.py
    from typing import Dict, Any, List
    from claude_code_sdk import Skill, SkillContext, SkillResult
    import re

    class PEP8CheckerSkill(Skill):
        """PEP 8 代码风格检查技能"""

        def __init__(self):
            super().__init__(
                name="pep8-checker",
                version="1.0.0",
                description="PEP 8 style checker"
            )

        def get_parameters_schema(self) -> Dict[str, Any]:
            return {
                "type": "object",
                "properties": {
                    "file_path": {
                        "type": "string",
                        "description": "Path to the file to check"
                    },
                    "code": {
                        "type": "string",
                        "description": "Code to check"
                    },
                    "max_line_length": {
                        "type": "integer",
                        "description": "Maximum line length",
                        "default": 79
                    }
                }
            }

        def execute(self, parameters: Dict[str, Any], context: SkillContext) -> SkillResult:
            try:
                max_line_length = parameters.get("max_line_length", 79)

                # 获取代码
                if "file_path" in parameters:
                    code = context.read_file(parameters["file_path"])
                    file_path = parameters["file_path"]
                elif "code" in parameters:
                    code = parameters["code"]
                    file_path = "<inline>"
                else:
                    return SkillResult(
                        success=False,
                        error="Either file_path or code must be provided"
                    )

                # 执行检查
                violations = self.check_pep8(code, max_line_length)

                return SkillResult(
                    success=True,
                    data={
                        "file_path": file_path,
                        "max_line_length": max_line_length,
                        "violations": violations,
                        "violation_count": len(violations)
                    }
                )
            except Exception as e:
                return SkillResult(
                    success=False,
                    error=str(e)
                )

        def check_pep8(self, code: str, max_line_length: int) -> List[Dict]:
            """检查 PEP 8 规范"""
            violations = []
            lines = code.split('\n')

            for i, line in enumerate(lines, 1):
                # 检查行长度
                if len(line) > max_line_length:
                    violations.append({
                        "line": i,
                        "code": "E501",
                        "message": f"Line too long ({len(line)} > {max_line_length} characters)",
                        "severity": "warning"
                    })

                # 检查尾随空格
                if line.rstrip() != line.rstrip('\n').rstrip('\r'):
                    violations.append({
                        "line": i,
                        "code": "W291",
                        "message": "Trailing whitespace",
                        "severity": "warning"
                    })

                # 检查空行
                if line.strip() == "" and i < len(lines):
                    # 检查连续空行
                    if i > 1 and lines[i-2].strip() == "" and lines[i-1].strip() == "":
                        violations.append({
                            "line": i,
                            "code": "E303",
                            "message": "Too many blank lines",
                            "severity": "info"
                        })

                # 检查导入顺序
                if line.strip().startswith("import ") or line.strip().startswith("from "):
                    if i > 1 and lines[i-2].strip() and not (
                        lines[i-2].strip().startswith("import ") or
                        lines[i-2].strip().startswith("from ")
                    ):
                        violations.append({
                            "line": i,
                            "code": "E402",
                            "message": "Module level import not at top of file",
                            "severity": "error"
                        })

            return violations

    ### 3. 代码重复检测

    #### 3.1 重复代码检查

    ```python

    # src/skills/duplicate_detector.py

```python
    from typing import Dict, Any, List, Tuple
    from claude_code_sdk import Skill, SkillContext, SkillResult
    import difflib

    class DuplicateDetectorSkill(Skill):
        """重复代码检测技能"""

        def __init__(self):
            super().__init__(
                name="duplicate-detector",
                version="1.0.0",
                description="Detect duplicate code blocks"
            )

        def get_parameters_schema(self) -> Dict[str, Any]:
            return {
                "type": "object",
                "properties": {
                    "file_path": {
                        "type": "string",
                        "description": "Path to the file to check"
                    },
                    "code": {
                        "type": "string",
                        "description": "Code to check"
                    },
                    "min_lines": {
                        "type": "integer",
                        "description": "Minimum number of lines to consider as duplicate",
                        "default": 5
                    },
                    "similarity_threshold": {
                        "type": "number",
                        "description": "Similarity threshold (0.0 to 1.0)",
                        "default": 0.8
                    }
                }
            }

        def execute(self, parameters: Dict[str, Any], context: SkillContext) -> SkillResult:
    try:
    min_lines = parameters.get("min_lines", 5)
    similarity_threshold = parameters.get("similarity_threshold", 0.8)

                # 获取代码
    if "file_path" in parameters:
    code = context.read_file(parameters["file_path"])
    file_path = parameters["file_path"]
    elif "code" in parameters:
    code = parameters["code"]
    file_path = "<inline>"
    else:
    return SkillResult(
    success=False,
    error="Either file_path or code must be provided"
            )

                # 检测重复
    duplicates = self.detect_duplicates(code, min_lines, similarity_threshold)
    return SkillResult(
    success=True,
    data={
    "file_path": file_path,
    "min_lines": min_lines,
    "similarity_threshold": similarity_threshold,
    "duplicates": duplicates,
    "duplicate_count": len(duplicates)
            }
        )
    except Exception as e:
    return SkillResult(
    success=False,
    error=str(e)
        )

        def detect_duplicates(self, code: str, min_lines: int,
                         similarity_threshold: float) -> List[Dict]:
            """检测重复代码块"""
            lines = code.split('\n')
            duplicates = []

            # 提取代码块
    blocks = self.extract_blocks(lines, min_lines)
    # 比较所有块对
    for i, block1 in enumerate(blocks):
    for j, block2 in enumerate(blocks):
    if i >= j:
    continue
    similarity = self.calculate_similarity(block1["code"], block2["code"])
    if similarity >= similarity_threshold:
                duplicates.append({
    "block1": {
    "start_line": block1["start_line"],
    "end_line": block1["end_line"],
    "code": block1["code"]
    },
    "block2": {
    "start_line": block2["start_line"],
    "end_line": block2["end_line"],
    "code": block2["code"]
    },
    "similarity": similarity,
    "suggestion": "Consider extracting common code into a function"
            })

            return duplicates

        def extract_blocks(self, lines: List[str], min_lines: int) -> List[Dict]:
    """提取代码块"""
    blocks = []
    for i in range(len(lines) - min_lines + 1):
    block_code = '\n'.join(lines[i:i+min_lines])
    blocks.append({
    "start_line": i + 1,
    "end_line": i + min_lines,
    "code": block_code
    })
    return blocks
    def calculate_similarity(self, code1: str, code2: str) -> float:
    """计算代码相似度"""
    # 使用序列匹配器
    matcher = difflib.SequenceMatcher(None, code1, code2)
    return matcher.ratio()

## 使用示例

### 1\. 完整代码审查

    bash


    python

    # examples/code_review.py
    from skills.code_reviewer import CodeReviewerSkill
    from claude_code_sdk import SkillContext

    skill = CodeReviewerSkill()
    context = SkillContext()

    result = skill.execute(
        {
            "file_path": "src/main.py",
            "language": "python",
            "rules": ["naming", "complexity", "security", "performance", "documentation"],
            "severity": "all"
        },
        context
    )

    print(f"Found {result.data['issue_count']} issues")
    print(result.data["report"])

### 2\. PEP 8 检查

    python


    # examples/pep8_check.py
    from skills.pep8_checker import PEP8CheckerSkill
    from claude_code_sdk import SkillContext

    skill = PEP8CheckerSkill()
    context = SkillContext()

    result = skill.execute(
        {
    "file_path": "src/main.py",
    "max_line_length": 79
    },
    context
    )
    print(f"Found {result.data['violation_count']} PEP 8 violations")
    for violation in result.data["violations"]:
    print(f"Line {violation['line']}: {violation['message']}")

### 3\. 重复代码检测

    bash


    python

    # examples/duplicate_detection.py
    from skills.duplicate_detector import DuplicateDetectorSkill
    from claude_code_sdk import SkillContext

    skill = DuplicateDetectorSkill()
    context = SkillContext()

    result = skill.execute(
        {
            "file_path": "src/main.py",
            "min_lines": 5,
            "similarity_threshold": 0.8
        },
        context
    )

    print(f"Found {result.data['duplicate_count']} duplicate blocks")
    for duplicate in result.data["duplicates"]:
        print(f"Lines {duplicate['block1']['start_line']}-{duplicate['block1']['end_line']} "
              f"similar to lines {duplicate['block2']['start_line']}-{duplicate['block2']['end_line']} "
              f"(similarity: {duplicate['similarity']:.2f})")

    ## 最佳实践

    ### 1. 审查规则配置

    #### 1. 规则优先级
    - 安全规则:最高优先级
    - 性能规则:高优先级
    - 代码质量:中优先级
    - 代码风格:低优先级
    ### 2. 规则定制
    - 根据项目需求定制规则
    - 考虑团队编码规范
    - 逐步引入新规则
    ### 3. 规则例外
    - 提供规则例外机制
    - 记录例外原因
    - 定期审查例外

### 2\. 审查流程

    bash


    markdown

    #### 1. 自动审查
    - 在提交前自动运行
    - 集成到 CI/CD 流程
    - 阻止不符合规范的代码

    ### 2. 人工审查
    - 审查自动审查结果
    - 关注复杂逻辑
    - 提供建设性反馈

    ### 3. 持续改进
    - 收集审查反馈
    - 优化审查规则
    - 提高审查效率

## 总结

代码审查技能可以帮助团队自动化代码审查流程,提高代码质量和一致性。通过合理配置审查规则和流程,可以显著减少代码中的问题,提高开发效率。

在下一节中,我们将探讨文档生成技能。

基于 MIT 许可发布 | 永久导航