Skip to content

核心合并逻辑存在架构性缺陷,导致四个可复现的阻塞级 Bug* #41

@wlvh

Description

@wlvh

引言 (Introduction)

收到了关于 CI 中持续失败用例的详细分析报告。这份报告质量很高,其列出的四个阻塞性缺陷(B1-B4)与我之前从架构层面指出的脆弱性完全吻合。这再次证明,当前合并器的核心逻辑已经不可靠,必须进行根本性修复,而非表面修补。

我将整合这份详细的分析,发布一份权威的、指导性的 Issue,作为后续所有相关修复工作的唯一参考。


Canonical Issue #40 (重构版): 核心合并逻辑存在架构性缺陷,导致四个可复现的阻塞级 Bug

  • 标签 (Labels): bug, priority:critical, architecture, refactor, merger-logic
  • 状态 (Status): Open

1. 背景与现象 (Background & Phenomena)

在 PR「增强变量绑定与作用域隔离」合并后,ASTAuditor 的健壮性得到提升,但这反而更加暴露了合并器 advanced_merge.py 自身的严重缺陷。当前 CI 中持续的测试失败,均由合并器逻辑引起。

具体现象与我分析的根因对应如下:

现象 ID 具体表现 (Symptom) 根因分析 (Root Cause Analysis)
F-1 本应抛出 CircularDependencyError 的用例,执行时畅通无阻。 依赖图构建不完整ContextAwareVisitor 这个“上帝对象”未能捕捉到所有依赖边,导致提供给拓扑排序算法的是一张错误的、没有环路的图。
F-2 super().__init__() 等属性调用链,在合并后被错误截断为裸的 __init__ 错误的属性访问转换AdvancedNodeTransformer.visit_Attribute 在替换属性链的根节点时,逻辑存在缺陷,直接丢弃了后续的属性访问 (.attr)。
F-3 合并后的代码运行时出现 NameErrorTypeError 失败的符号冲突策略。当用户定义的函数名与导入的模块别名冲突时,generate_name_mappings 的决策失误,可能错误地重命名了用户代码,或产生了覆盖。
F-4 外部模块别名(Alias)的重命名策略混乱且不一致。 缺乏单一入口和状态管理。重命名逻辑分散在 _process_importsAdvancedNodeTransformer 中,导致对同一个别名进行多次、不同规则的重命名。

2. 修复标准 (Acceptance Criteria / Expected Behavior)

  1. 循环依赖 (F-1): 任何存在于代码逻辑中的循环依赖,必须被检测到,并抛出 CircularDependencyError,报告中应包含清晰的循环路径。
  2. 属性链 (F-2): 任何属性调用链(如 a.b.c, super().__init__)在合并后必须保持其完整结构,不允许任何形式的截断。
  3. 命名冲突 (F-3): 当用户代码(函数/类)与导入别名冲突时,必须优先重命名导入别名,绝不允许修改用户定义的符号名称。
  4. 别名后缀 (F-4): 必须采用统一且无歧义的别名重命名策略,并在整个合并流程中只执行一次。我在此规定:
    • 静态外部导入:xxxxxx__mod
    • 运行时导入 (try/except):xxxxxx__rt

3. 建议的修复路线与任务清单 (Suggested Fix Route & Task List)

请严格按照以下路线图执行修复,不要偏离。

  • [ ] 修复 F-2 (属性链截断)

    • 方法: 这是最直接的修复。修改 AdvancedNodeTransformer.visit_Attribute,确保在递归访问 node.value 后,用返回的新节点重新构建 ast.Attribute
      # In AdvancedNodeTransformer
      def visit_Attribute(self, node: ast.Attribute) -> ast.AST:
          # 1. 递归访问并替换属性链的根 (base)
          new_base = self.visit(node.value)
          
          # 2. 用新的 base 和旧的 attr 重建节点,保证属性链不丢失
          return ast.Attribute(value=new_base, attr=node.attr, ctx=node.ctx)
  • [ ] 修复 F-4 (别名命名混乱)

    • 方法: 统一改名入口,避免重复执行。
      1. 移除 _process_imports 中的所有重命名逻辑,让它只负责去重。
      2. 所有重命名逻辑集中AdvancedNodeTransformervisit_Importvisit_ImportFrom 方法中。
      3. ast.alias 节点上设置一个临时标记(如 alias._renamed = True)来防止同一个节点被重复处理。
  • [ ] 修复 F-3 (命名冲突策略)

    • 方法: 在 generate_name_mappings_write_symbol 中明确决策逻辑。
      1. 当检测到名称冲突时,检查每个冲突符号的类型 (symbol.type)。
      2. 如果符号类型是 import_alias,则对其应用重命名。
      3. 如果符号类型是 functionclass,则保持其原名(除非存在多个同名函数/类)。
      4. 增加往返测试 (Round-trip Test):创建一个新的测试,先调用 advanced_merge.py 生成合并文件,然后 import 并执行该文件,断言其运行结果正确,没有抛出 NameErrorTypeError
  • [ ] 修复 F-1 (循环依赖检测)

    • 方法: 这个问题根源最深,在前三者修复之后处理。
      1. 深入调试 ContextAwareVisitor,特别是 analyze_dependencies 方法。
      2. 针对失败的用例,手动画出正确的依赖图,然后对比程序生成的 symbol.dependencies,找出缺失的依赖边
      3. topological_sort 的末尾增加断言:检查图中是否还存在入度大于 0 的节点。如果存在,说明环路依然存在,此时应打印出这些节点的详细信息以辅助调试。
  • [ ] CI 与兼容性:

    • 移除对 Python 3.8 的支持,或为 ast.unparse 等不兼容的 API 引入兼容层,以保证 CI 的稳定。

重申:Issue #41 依然有效

最后,我必须重申,我之前提交的 Issue #41: ASTAuditor 的属性验证存在致命盲区 依然是开放且关键的。它与此处的合并器问题是独立的。在修复完合并器的这些缺陷后,必须立即着手解决审计器的“虚假安全感”问题。

将这份整合后的 Issue 分配下去。我要求看到的是针对这些根本问题的架构性修复,而不是更多的临时补丁。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions