第5讲:代码审查与 Bug 检测

第4讲我们实现了自然语言转代码------MiniCopilot 能根据用户描述生成代码。但生成的代码质量如何?有没有隐藏的 Bug?这一讲,我们要让 MiniCopilot 学会审查代码,像一位经验丰富的代码评审员一样,自动发现潜在问题。


一、代码审查的核心维度

维度 说明 示例
语法错误 代码无法通过编译/解释 缺少括号、缩进错误
逻辑错误 代码能运行但结果不对 除零、无限循环、空指针
安全漏洞 可能存在安全隐患 SQL 注入、XSS、硬编码密钥
性能问题 代码效率低下 不必要的循环、重复计算
代码异味 代码可维护性差 过长函数、魔法数字、重复代码
最佳实践 违反语言惯例 命名不规范、缺少类型注解

二、静态分析引擎

2.1 基于规则的检测器

复制代码
# engine/analyzer/rules/base.py
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Optional

@dataclass
class Issue:
    """代码问题"""
    rule_id: str
    severity: str  # error / warning / info
    message: str
    line: int
    column: int
    suggestion: Optional[str] = None
    code_snippet: Optional[str] = None

class Rule(ABC):
    """检测规则基类"""
    
    @abstractmethod
    def check(self, node, code: str) -> list[Issue]:
        """检查代码节点,返回发现的问题"""
        pass
    
    @property
    @abstractmethod
    def rule_id(self) -> str:
        pass
    
    @property
    @abstractmethod
    def description(self) -> str:
        pass

2.2 具体规则实现

复制代码
# engine/analyzer/rules/python_rules.py
from .base import Rule, Issue

class BareExceptRule(Rule):
    """检测裸 except"""
    
    rule_id = "E001"
    description = "检测没有指定异常类型的 except 语句"
    
    def check(self, node, code: str) -> list[Issue]:
        issues = []
        if node.type == "except_clause" and not any(
            child.type == "type" for child in node.children
        ):
            issues.append(Issue(
                rule_id=self.rule_id,
                severity="warning",
                message="使用裸 except 会捕获所有异常,包括 SystemExit 和 KeyboardInterrupt",
                line=node.range.start.line + 1,
                column=node.range.start.column,
                suggestion="改为 except Exception as e: 来捕获特定异常"
            ))
        return issues

class HardcodedPasswordRule(Rule):
    """检测硬编码密码"""
    
    rule_id = "S001"
    description = "检测代码中硬编码的密码或密钥"
    
    # 常见的密码变量名
    SENSITIVE_NAMES = {"password", "passwd", "secret", "api_key", "token", "credential"}
    
    def check(self, node, code: str) -> list[Issue]:
        issues = []
        
        # 检查赋值语句
        if node.type == "assignment":
            left = node.children[0] if node.children else None
            right = node.children[-1] if len(node.children) > 1 else None
            
            if left and left.type == "identifier":
                var_name = left.text.lower()
                if var_name in self.SENSITIVE_NAMES:
                    issues.append(Issue(
                        rule_id=self.rule_id,
                        severity="error",
                        message=f"检测到可能的硬编码凭据: {left.text}",
                        line=node.range.start.line + 1,
                        column=node.range.start.column,
                        suggestion="使用环境变量或密钥管理服务来存储敏感信息"
                    ))
        
        return issues

class LongFunctionRule(Rule):
    """检测过长函数"""
    
    rule_id = "C001"
    description = "检测过长的函数(超过50行)"
    
    def check(self, node, code: str) -> list[Issue]:
        issues = []
        
        if node.type == "function_definition":
            func_lines = node.range.end.line - node.range.start.line
            if func_lines > 50:
                # 获取函数名
                func_name = ""
                for child in node.children:
                    if child.type == "identifier":
                        func_name = child.text
                        break
                
                issues.append(Issue(
                    rule_id=self.rule_id,
                    severity="warning",
                    message=f"函数 '{func_name}' 过长({func_lines}行),建议拆分",
                    line=node.range.start.line + 1,
                    column=node.range.start.column,
                    suggestion="考虑将函数拆分为多个小函数,每个函数只做一件事"
                ))
        
        return issues

class MagicNumberRule(Rule):
    """检测魔法数字"""
    
    rule_id = "C002"
    description = "检测没有命名的硬编码数值"
    
    def check(self, node, code: str) -> list[Issue]:
        issues = []
        
        # 检测数字字面量(排除 0, 1, -1, True, False 等常见值)
        if node.type == "integer" or node.type == "float":
            try:
                value = float(node.text)
                # 跳过常见的无害数字
                if value in (0, 1, -1, 100) or value == int(value):
                    return issues
                
                # 检查是否在比较表达式中
                if node.parent and node.parent.type in ("comparison_operator", "binary_operator"):
                    issues.append(Issue(
                        rule_id=self.rule_id,
                        severity="info",
                        message=f"魔法数字 {node.text},建议定义为命名常量",
                        line=node.range.start.line + 1,
                        column=node.range.start.column,
                        suggestion=f"例如: MAX_RETRIES = {node.text}"
                    ))
            except:
                pass
        
        return issues

class TodoCommentRule(Rule):
    """检测 TODO 注释"""
    
    rule_id = "C003"
    description = "检测遗留的 TODO/FIXME 注释"
    
    def check(self, node, code: str) -> list[Issue]:
        issues = []
        
        if node.type == "comment":
            text = node.text.lower()
            if "todo" in text or "fixme" in text or "hack" in text:
                issues.append(Issue(
                    rule_id=self.rule_id,
                    severity="info",
                    message=f"发现遗留标记: {node.text.strip()}",
                    line=node.range.start.line + 1,
                    column=node.range.start.column,
                    suggestion="在提交前处理此标记"
                ))
        
        return issues

2.3 规则引擎

复制代码
# engine/analyzer/rules/engine.py
from engine.parser.python_parser import PythonParser
from .python_rules import (
    BareExceptRule, HardcodedPasswordRule,
    LongFunctionRule, MagicNumberRule, TodoCommentRule
)

class RuleEngine:
    """规则引擎:遍历 AST 并应用所有规则"""
    
    def __init__(self, language: str = "python"):
        self.language = language
        self.parser = PythonParser() if language == "python" else None
        
        # 注册规则
        self.rules = self._register_rules()
    
    def _register_rules(self) -> list:
        """注册所有规则"""
        return [
            BareExceptRule(),
            HardcodedPasswordRule(),
            LongFunctionRule(),
            MagicNumberRule(),
            TodoCommentRule(),
        ]
    
    def analyze(self, code: str) -> list[Issue]:
        """
        分析代码,返回所有发现的问题
        
        参数:
            code: 源代码
        
        返回:
            [Issue, ...] 按行号排序的问题列表
        """
        if not self.parser:
            return []
        
        # 解析 AST
        ast = self.parser.parse(code)
        
        # 遍历 AST 并应用规则
        all_issues = []
        self._walk_and_check(ast, code, all_issues)
        
        # 按行号排序
        all_issues.sort(key=lambda x: (x.line, x.column))
        
        return all_issues
    
    def _walk_and_check(self, node, code: str, issues: list):
        """递归遍历 AST 节点并应用规则"""
        
        # 对当前节点应用所有规则
        for rule in self.rules:
            try:
                rule_issues = rule.check(node, code)
                issues.extend(rule_issues)
            except Exception as e:
                print(f"规则 {rule.rule_id} 执行出错: {e}")
        
        # 递归子节点
        for child in node.children:
            self._walk_and_check(child, code, issues)
    
    def get_summary(self, issues: list[Issue]) -> dict:
        """获取问题摘要"""
        summary = {
            "total": len(issues),
            "by_severity": {"error": 0, "warning": 0, "info": 0},
            "by_rule": {}
        }
        
        for issue in issues:
            summary["by_severity"][issue.severity] = \
                summary["by_severity"].get(issue.severity, 0) + 1
            
            if issue.rule_id not in summary["by_rule"]:
                summary["by_rule"][issue.rule_id] = 0
            summary["by_rule"][issue.rule_id] += 1
        
        return summary

三、LLM 驱动的深度审查

静态规则能发现已知模式的问题,但对于复杂的逻辑错误、设计问题,需要 LLM 的理解能力。

复制代码
# engine/analyzer/llm_reviewer.py
import requests
import json

class LLMCodeReviewer:
    """基于 LLM 的代码审查"""
    
    def __init__(self, api_key: str):
        self.api_key = api_key
    
    def review(self, code: str, language: str = "python", 
               context: str = "") -> dict:
        """
        深度审查代码
        
        返回:
        {
            "overall_assessment": "总体评价",
            "bugs": [{"severity", "description", "line", "suggestion"}],
            "security_issues": [...],
            "performance_issues": [...],
            "design_issues": [...],
            "improvements": [...]
        }
        """
        prompt = self._build_review_prompt(code, language, context)
        
        response = requests.post(
            "https://api.deepseek.com/v1/chat/completions",
            headers={"Authorization": f"Bearer {self.api_key}"},
            json={
                "model": "deepseek-chat",
                "messages": [
                    {"role": "system", "content": "你是一位资深的代码审查专家。请全面审查代码,发现 Bug、安全漏洞、性能问题和设计缺陷。"},
                    {"role": "user", "content": prompt}
                ],
                "response_format": {"type": "json_object"},
                "temperature": 0.2,
                "max_tokens": 4096
            }
        )
        
        result = response.json()
        content = result["choices"][0]["message"]["content"]
        
        try:
            review_result = json.loads(content)
            return review_result
        except:
            return {
                "overall_assessment": "审查失败",
                "bugs": [{"severity": "error", "description": "无法解析 LLM 响应"}],
                "security_issues": [],
                "performance_issues": [],
                "design_issues": [],
                "improvements": []
            }
    
    def _build_review_prompt(self, code: str, language: str, context: str) -> str:
        return f"""请全面审查以下 {language} 代码。

代码:

{language}

{code}

复制代码
{context}

请输出 JSON 格式的审查结果,包含以下字段:
1. overall_assessment: 总体评价(优秀/良好/一般/需改进)
2. bugs: Bug 列表,每个包含 severity(critical/major/minor)、description、line_number(如果可确定)、suggestion
3. security_issues: 安全问题列表
4. performance_issues: 性能问题列表
5. design_issues: 设计问题列表(如单一职责、耦合度等)
6. improvements: 改进建议列表

重点关注:
- 潜在的运行时错误(空指针、除零、类型错误)
- 并发安全问题(竞态条件、死锁)
- 资源泄漏(文件句柄、数据库连接未关闭)
- 逻辑错误(边界条件处理不当)
- 安全漏洞(注入、XSS、敏感信息泄露)
- 性能瓶颈(不必要的循环、重复计算)
- 代码可维护性(过长函数、过度嵌套、魔法数字)"""

四、混合审查引擎

结合静态规则和 LLM 的优势:

复制代码
# engine/analyzer/hybrid_reviewer.py
from .rules.engine import RuleEngine
from .llm_reviewer import LLMCodeReviewer

class HybridReviewer:
    """混合审查引擎"""
    
    def __init__(self, api_key: str):
        self.rule_engine = RuleEngine()
        self.llm_reviewer = LLMCodeReviewer(api_key)
    
    def review(self, code: str, language: str = "python",
               deep_analysis: bool = True) -> dict:
        """
        混合审查代码
        
        策略:
        1. 先用规则引擎快速扫描(< 100ms)
        2. 如果发现问题较多或需要深度分析,调用 LLM
        3. 合并结果,去重
        """
        result = {
            "static_issues": [],
            "deep_review": None,
            "summary": {},
            "quality_score": 0
        }
        
        # 1. 静态规则检查
        static_issues = self.rule_engine.analyze(code)
        result["static_issues"] = [
            {
                "rule_id": i.rule_id,
                "severity": i.severity,
                "message": i.message,
                "line": i.line,
                "suggestion": i.suggestion
            }
            for i in static_issues
        ]
        
        # 2. LLM 深度审查(可选)
        if deep_analysis:
            deep_review = self.llm_reviewer.review(code, language)
            result["deep_review"] = deep_review
        
        # 3. 计算综合评分
        result["quality_score"] = self._calculate_score(result)
        
        # 4. 生成摘要
        result["summary"] = self._generate_summary(result)
        
        return result
    
    def _calculate_score(self, result: dict) -> int:
        """计算代码质量评分(0-100)"""
        score = 100
        
        # 静态规则扣分
        for issue in result["static_issues"]:
            if issue["severity"] == "error":
                score -= 15
            elif issue["severity"] == "warning":
                score -= 8
            else:
                score -= 3
        
        # LLM 审查扣分
        deep = result.get("deep_review", {})
        if deep:
            score -= len(deep.get("bugs", [])) * 10
            score -= len(deep.get("security_issues", [])) * 12
            score -= len(deep.get("performance_issues", [])) * 5
        
        return max(0, min(100, score))
    
    def _generate_summary(self, result: dict) -> dict:
        """生成审查摘要"""
        static_count = len(result["static_issues"])
        error_count = sum(1 for i in result["static_issues"] if i["severity"] == "error")
        warning_count = sum(1 for i in result["static_issues"] if i["severity"] == "warning")
        
        summary = {
            "total_issues": static_count,
            "errors": error_count,
            "warnings": warning_count,
            "quality_score": result["quality_score"]
        }
        
        # 添加 LLM 审查摘要
        deep = result.get("deep_review", {})
        if deep:
            summary["bugs_found"] = len(deep.get("bugs", []))
            summary["security_issues"] = len(deep.get("security_issues", []))
            summary["performance_issues"] = len(deep.get("performance_issues", []))
            summary["overall_assessment"] = deep.get("overall_assessment", "未知")
        
        return summary

五、Bug 检测实战

5.1 常见 Bug 模式检测

复制代码
# engine/analyzer/bug_detector.py
import re

class BugDetector:
    """Bug 检测器:专门检测常见 Bug 模式"""
    
    def detect(self, code: str, language: str = "python") -> list[dict]:
        """检测代码中的 Bug"""
        bugs = []
        
        detectors = [
            self._check_division_by_zero,
            self._check_infinite_loop,
            self._check_none_dereference,
            self._check_resource_leak,
            self._check_race_condition,
        ]
        
        for detector in detectors:
            try:
                found = detector(code)
                bugs.extend(found)
            except Exception as e:
                print(f"检测器 {detector.__name__} 出错: {e}")
        
        return bugs
    
    def _check_division_by_zero(self, code: str) -> list[dict]:
        """检测可能的除零操作"""
        bugs = []
        
        # 模式:直接除以字面量 0
        for match in re.finditer(r'/[\s]*0[\s]*[^.]', code):
            line_num = code[:match.start()].count('\n') + 1
            bugs.append({
                "type": "division_by_zero",
                "severity": "critical",
                "message": "可能的除零操作",
                "line": line_num,
                "suggestion": "在进行除法前检查除数是否为0"
            })
        
        # 模式:变量可能为0但没有检查
        div_pattern = re.finditer(r'/(\w+)', code)
        for match in div_pattern:
            var_name = match.group(1)
            # 检查这个变量之前有没有非零检查
            line_start = max(0, match.start() - 200)
            before = code[line_start:match.start()]
            if var_name not in before:  # 简单启发式
                line_num = code[:match.start()].count('\n') + 1
                bugs.append({
                    "type": "potential_division_by_zero",
                    "severity": "major",
                    "message": f"变量 '{var_name}' 用作除数但未检查是否为0",
                    "line": line_num,
                    "suggestion": f"添加 if {var_name} == 0: 的处理"
                })
        
        return bugs
    
    def _check_infinite_loop(self, code: str) -> list[dict]:
        """检测可能的无限循环"""
        bugs = []
        
        # 检测 while True 没有 break
        lines = code.split('\n')
        for i, line in enumerate(lines):
            stripped = line.strip()
            if stripped == 'while True:' or stripped == 'while 1:':
                # 检查后续代码是否有 break
                following = '\n'.join(lines[i:i+30])
                if 'break' not in following:
                    bugs.append({
                        "type": "infinite_loop",
                        "severity": "critical",
                        "message": "while True 循环中没有找到 break 语句",
                        "line": i + 1,
                        "suggestion": "添加循环退出条件或 break 语句"
                    })
        
        # 检测 for 循环中修改迭代变量
        for match in re.finditer(r'for (\w+) in', code):
            var_name = match.group(1)
            after = code[match.end():match.end()+500]
            # 检查迭代变量是否被修改
            if re.search(rf'\b{var_name}\s*=', after):
                line_num = code[:match.start()].count('\n') + 1
                bugs.append({
                    "type": "modified_iterator",
                    "severity": "warning",
                    "message": f"循环变量 '{var_name}' 在循环体内被修改,可能导致意外行为",
                    "line": line_num,
                    "suggestion": "使用不同的变量名来存储修改后的值"
                })
        
        return bugs
    
    def _check_none_dereference(self, code: str) -> list[dict]:
        """检测可能的空指针/None 解引用"""
        bugs = []
        
        # 检测函数返回值可能为 None 但没有检查
        none_return_functions = ['find', 'get', 'first_or_null', 'optional']
        
        for func in none_return_functions:
            pattern = rf'{func}\(.*?\)\.'
            for match in re.finditer(pattern, code):
                before = code[max(0, match.start()-100):match.start()]
                # 检查前面是否有 None 检查
                if 'is None' not in before and 'is not None' not in before:
                    line_num = code[:match.start()].count('\n') + 1
                    bugs.append({
                        "type": "none_dereference",
                        "severity": "critical",
                        "message": f"'{func}()' 的返回值可能为 None,直接访问属性可能引发 AttributeError",
                        "line": line_num,
                        "suggestion": f"先检查返回值是否为 None: result = {func}(...); if result is not None:"
                    })
        
        return bugs
    
    def _check_resource_leak(self, code: str) -> list[dict]:
        """检测资源泄漏"""
        bugs = []
        
        # 检测 open() 没有使用 with 语句
        for match in re.finditer(r'\bopen\(', code):
            before = code[:match.start()]
            # 检查是否在 with 语句中
            line_start = before.rfind('\n') + 1 if '\n' in before else 0
            line_prefix = before[line_start:]
            
            if 'with' not in line_prefix:
                line_num = code[:match.start()].count('\n') + 1
                bugs.append({
                    "type": "resource_leak",
                    "severity": "major",
                    "message": "文件打开操作未使用 with 语句,可能导致文件句柄泄漏",
                    "line": line_num,
                    "suggestion": "使用 'with open(...) as f:' 确保文件自动关闭"
                })
        
        return bugs
    
    def _check_race_condition(self, code: str) -> list[dict]:
        """检测可能的竞态条件"""
        bugs = []
        
        # 检测文件操作没有加锁
        if 'threading' in code or 'Thread' in code:
            file_ops = re.finditer(r'(open|write|read)\s*\(', code)
            has_lock = 'Lock' in code or 'RLock' in code
            
            if file_ops and not has_lock:
                for match in file_ops:
                    line_num = code[:match.start()].count('\n') + 1
                    bugs.append({
                        "type": "race_condition",
                        "severity": "major",
                        "message": "多线程环境下进行文件操作但没有使用锁",
                        "line": line_num,
                        "suggestion": "使用 threading.Lock() 保护共享资源的访问"
                    })
                    break  # 只报告一次
        
        return bugs

5.2 完整审查演示

复制代码
# test_reviewer.py
from engine.analyzer.hybrid_reviewer import HybridReviewer
from engine.analyzer.bug_detector import BugDetector
import json

# 初始化
api_key = "your-api-key"
reviewer = HybridReviewer(api_key)
bug_detector = BugDetector()

# 测试代码(故意包含各种问题)
test_code = """
import os

def process_user_data(user_input):
    # TODO: 添加输入验证
    query = "SELECT * FROM users WHERE id = " + user_input
    os.system("echo " + user_input)
    
    result = find_user(user_input)
    return result.name

def calculate_discount(price, rate):
    result = price / rate
    return result

def read_config():
    file = open("config.txt")
    data = file.read()
    return data

def complex_function(a, b, c, d, e, f, g, h, i, j):
    x = a + b
    y = c * d
    z = e - f
    w = g / h
    v = i ** j
    result = x + y + z + w + v
    result = result * 42
    result = result / 7
    result = result - 12345
    return result

password = "supersecret123"

while True:
    print("Running...")
"""

print("=" * 60)
print("🔍 代码审查报告")
print("=" * 60)

# 1. 静态规则检查
print("\n📋 静态规则检查:")
result = reviewer.review(test_code, deep_analysis=False)

for issue in result["static_issues"]:
    icon = {"error": "❌", "warning": "⚠️", "info": "ℹ️"}
    print(f"  {icon.get(issue['severity'], '•')} [{issue['severity'].upper()}] "
          f"第{issue['line']}行: {issue['message']}")
    if issue.get('suggestion'):
        print(f"    💡 {issue['suggestion']}")

print(f"\n📊 统计: {result['summary']['total_issues']} 个问题 "
      f"(错误: {result['summary']['errors']}, "
      f"警告: {result['summary']['warnings']})")

# 2. Bug 检测
print("\n🐛 Bug 检测:")
bugs = bug_detector.detect(test_code)
for bug in bugs:
    print(f"  [{bug['severity'].upper()}] 第{bug['line']}行: {bug['message']}")
    print(f"    💡 {bug['suggestion']}")

# 3. LLM 深度审查
print("\n🧠 LLM 深度审查:")
deep_result = reviewer.review(test_code, deep_analysis=True)

if deep_result.get("deep_review"):
    dr = deep_result["deep_review"]
    print(f"\n总体评价: {dr.get('overall_assessment', '未知')}")
    
    for bug in dr.get("bugs", []):
        print(f"  ❌ [{bug.get('severity', 'unknown')}] {bug.get('description', '')}")
        if bug.get('suggestion'):
            print(f"     💡 {bug['suggestion']}")
    
    for sec in dr.get("security_issues", []):
        print(f"  🔒 {sec}")
    
    for perf in dr.get("performance_issues", []):
        print(f"  ⚡ {perf}")

# 4. 最终评分
print(f"\n{'=' * 60}")
print(f"🏆 代码质量评分: {result['quality_score']}/100")
if result['quality_score'] >= 80:
    print("✅ 代码质量良好")
elif result['quality_score'] >= 60:
    print("⚠️ 代码需要改进")
else:
    print("❌ 代码存在严重问题")

六、IDE 集成:代码诊断

复制代码
# plugin/diagnostics.py
class DiagnosticProvider:
    """IDE 诊断提供者"""
    
    def __init__(self, reviewer):
        self.reviewer = reviewer
        self.diagnostics = {}
    
    def update_diagnostics(self, file_path: str, code: str):
        """更新文件的诊断信息"""
        result = self.reviewer.review(code, deep_analysis=False)
        
        diagnostics = []
        
        # 转换问题为 IDE 诊断格式
        for issue in result["static_issues"]:
            severity_map = {
                "error": 1,      # Error
                "warning": 2,    # Warning
                "info": 3,       # Information
            }
            
            diagnostic = {
                "range": {
                    "start": {"line": issue["line"] - 1, "character": 0},
                    "end": {"line": issue["line"] - 1, "character": 100}
                },
                "severity": severity_map.get(issue["severity"], 3),
                "message": issue["message"],
                "source": "MiniCopilot",
                "code": issue.get("rule_id", "unknown"),
                "relatedInformation": []
            }
            
            if issue.get("suggestion"):
                diagnostic["relatedInformation"].append({
                    "location": diagnostic["range"],
                    "message": f"💡 {issue['suggestion']}"
                })
            
            diagnostics.append(diagnostic)
        
        self.diagnostics[file_path] = diagnostics
        return diagnostics
    
    def get_diagnostics(self, file_path: str) -> list:
        """获取文件的诊断信息"""
        return self.diagnostics.get(file_path, [])

七、性能优化

7.1 增量审查

复制代码
class IncrementalReviewer:
    """增量审查:只审查变化的部分"""
    
    def __init__(self, reviewer):
        self.reviewer = reviewer
        self.file_versions = {}
    
    def review_change(self, file_path: str, old_code: str, new_code: str):
        """审查文件的变化"""
        if file_path not in self.file_versions:
            # 首次审查,全量检查
            result = self.reviewer.review(new_code)
            self.file_versions[file_path] = new_code
            return result
        
        # 计算差异
        import difflib
        diff = list(difflib.unified_diff(
            old_code.splitlines(keepends=True),
            new_code.splitlines(keepends=True)
        ))
        
        # 如果改动很小,只审查变化行
        if len(diff) < 20:
            changed_lines = set()
            for line in diff:
                if line.startswith('@@'):
                    # 解析行号
                    match = re.search(r'\+(\d+)', line)
                    if match:
                        changed_lines.add(int(match.group(1)))
            
            # 只审查变化行附近的代码
            context_lines = set()
            for line in changed_lines:
                for offset in range(-5, 6):
                    context_lines.add(line + offset)
            
            lines = new_code.split('\n')
            relevant_code = '\n'.join(
                lines[i] for i in range(len(lines))
                if i + 1 in context_lines
            )
            
            result = self.reviewer.review(relevant_code)
        else:
            # 改动较大,全量审查
            result = self.reviewer.review(new_code)
        
        self.file_versions[file_path] = new_code
        return result

八、常见错误 & 排坑指南

  1. 误报太多

    • 问题:规则引擎过于严格,产生大量误报

    • 解决:配置规则阈值,允许用户忽略某些规则

  2. LLM 审查不稳定

    • 问题:相同代码每次审查结果不同

    • 解决:降低 temperature,多次审查取交集

  3. 大型文件审查超时

    • 问题:超过千行的文件审查耗时过长

    • 解决:分段审查,只审查变更部分

  4. 安全规则误伤测试代码

    • 问题:测试代码中的硬编码密码被误报

    • 解决:根据文件路径自动调整规则集


九、课后作业

  1. 实现自定义规则:写一条规则检测"函数参数超过5个",这是代码坏味道之一。

  2. 添加安全规则:实现 SQL 注入检测规则,识别拼接 SQL 查询的代码。

  3. 挑战题:实现"自动修复建议"------对于常见问题(如裸 except),自动生成修复后的代码。


十、总结

这一讲我们实现了代码审查与 Bug 检测:

  • 静态规则引擎:基于 AST 的规则检查,快速发现已知模式的问题

  • LLM 深度审查:利用大模型的语义理解能力,发现复杂逻辑错误

  • Bug 检测器:专门检测除零、无限循环、空指针、资源泄漏等问题

  • 混合审查策略:规则引擎保速度,LLM 保深度

  • IDE 集成:将审查结果转换为 IDE 诊断信息

现在,MiniCopilot 不仅能写代码,还能像资深工程师一样审查代码质量。

下一讲,我们将实现单元测试自动生成------让 MiniCopilot 自动为代码生成测试用例。


🧰 开发之余,处理 Base64、JWT 解析、JSON 格式化、Crontab 计算、PDF 合并压缩这些碎片需求,我常用一个纯前端本地工具箱:zz365.top (子页 PDF 大师:PDF 大师 - zz365工具箱)。所有计算在浏览器完成,文件不上传服务器,关页即清。免费、无登录、无广告,适合开发者当常驻标签页。

相关推荐
netccdn1 小时前
Hough变换检测直线(Matlab)
开发语言·计算机视觉·matlab
有点。1 小时前
C++深度优先搜索(三)
开发语言·c++·深度优先
天空'之城1 小时前
C 语言工业级通用组件手写 25:简易日志系统
c语言·开发语言·日志系统·嵌入式调试·调试打印
程序喵大人1 小时前
【C++进阶】STL算法与函数对象 -【C++进阶】STL算法与函数对象
开发语言·c++·算法
weixin_BYSJ19871 小时前
【java项目分享】springboot阅读推荐平台10600
java·javascript·spring boot·python·django·flask·php
阿kun要赚马内2 小时前
工具在langchain agent中的调用
人工智能·后端·python
牛马也想出海2 小时前
使用Playwright被检测为机器人的原因及反检测方案
开发语言·网络·人工智能·机器人·php
GrowthDiary0072 小时前
Python 常用函数总结
开发语言·python
热心网友俣先生2 小时前
2026年华数杯C 题 超详细解题思路
c语言·开发语言·人工智能