You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AST遍历中Else块父条件上下文维护错误导致函数调用条件链生成异常

AST遍历中Else块父条件上下文维护错误导致函数调用条件链生成异常

我仔细看了你的代码和需求,核心问题出在条件上下文节点的维护逻辑上——处理else和else if块时,节点的父子链接、回溯时机都有偏差,导致无法正确生成嵌套的条件链。

问题根源拆解

  • else块处理逻辑错误:当你处理else对应的BlockStatement时,错误引用了currentConditionNode.parent.condition,但此时currentConditionNode已经是内层if的节点,导致取到的不是当前else对应的前置if条件。
  • else if的重复处理:你在enter阶段同时处理了普通IfStatement和else if类型的IfStatement,导致节点被重复添加,破坏了条件链的结构。
  • leave阶段的盲目回溯:不管当前IfStatement是主if还是else if,离开时都直接回溯到父节点,导致上下文提前回退,后续嵌套的条件无法正确叠加。

修复方案(修改后的完整代码)

针对这些问题,我调整了条件节点的维护逻辑,重点修正了else/else if的处理逻辑和回溯时机:

import esprima from 'esprima';
import estraverse from 'estraverse';
import escodegen from 'escodegen';

export function analyzeFunctionCalls(code, functionName, methods) {
    try {
        const ast = esprima.parseScript(code, { range: true, tokens: true, comment: true });
        const functionCalls = [];
        const variableMap = {};
        
        // 树形条件链管理(根节点无实际条件)
        let currentConditionNode = { 
            condition: null, 
            parent: null, 
            children: [] 
        };
        // 记录当前是否正在处理else分支,避免重复操作
        let isProcessingElse = false;

        estraverse.traverse(ast, {
            enter: (node, parent) => {
                // 变量声明处理
                if (node.type === 'VariableDeclaration') {
                    node.declarations.forEach(declaration => {
                        if (declaration.init) {
                            variableMap[declaration.id.name] = escodegen.generate(declaration.init);
                        }
                    });
                }

                // 处理普通IfStatement(非else if)
                if (node.type === 'IfStatement' && !isProcessingElse) {
                    const condition = processCondition(node.test, variableMap);
                    
                    // 创建新的条件节点并链接到当前节点
                    const newNode = {
                        condition: condition,
                        parent: currentConditionNode,
                        children: []
                    };
                    
                    currentConditionNode.children.push(newNode);
                    currentConditionNode = newNode;

                    // 如果当前if有else分支,标记接下来要处理else
                    if (node.alternate) {
                        isProcessingElse = true;
                    }
                }

                // 处理else if分支
                if (
                    node.type === 'IfStatement' &&
                    parent.type === 'IfStatement' &&
                    parent.alternate === node
                ) {
                    const currentIfCondition = currentConditionNode.condition;
                    const elseIfCondition = processCondition(node.test, variableMap);
                    
                    // 创建else if节点:条件为「非当前if条件 且 else if条件」
                    const newNode = {
                        condition: `非(${currentIfCondition}) 且 ${elseIfCondition}`,
                        parent: currentConditionNode.parent,
                        children: []
                    };
                    
                    currentConditionNode.parent.children.push(newNode);
                    currentConditionNode = newNode;

                    // 如果当前else if还有else分支,标记状态
                    if (node.alternate) {
                        isProcessingElse = true;
                    }
                }

                // 处理else块
                if (
                    node.type === 'BlockStatement' &&
                    parent.type === 'IfStatement' &&
                    parent.alternate === node
                    && isProcessingElse
                ) {
                    const currentIfCondition = currentConditionNode.condition;
                    
                    // 创建else节点:条件为「非当前if条件」
                    const newNode = {
                        condition: `非(${currentIfCondition})`,
                        parent: currentConditionNode.parent,
                        children: []
                    };
                    
                    currentConditionNode.parent.children.push(newNode);
                    currentConditionNode = newNode;
                    isProcessingElse = false;
                }

                // 收集函数调用
                if (node.type === 'CallExpression') {
                    const callee = node.callee;
                    const fullCondition = getFullConditionChain(currentConditionNode);
                    
                    if (
                        (callee.type === 'Identifier' && methods.includes(callee.name)) ||
                        (callee.type === 'MemberExpression' &&
                         callee.object.name === functionName &&
                         methods.includes(callee.property.name))
                    ) {
                        functionCalls.push({
                            call: escodegen.generate(node),
                            condition: fullCondition
                        });
                    }
                }
            },
            leave: (node, parent) => {
                // 仅当离开的是普通IfStatement(非else if),且不在else处理状态时回溯
                if (node.type === 'IfStatement' && !isProcessingElse && !(parent?.type === 'IfStatement' && parent.alternate === node)) {
                    currentConditionNode = currentConditionNode.parent;
                }
                // 离开else if的IfStatement时,重置状态
                if (node.type === 'IfStatement' && parent?.type === 'IfStatement' && parent.alternate === node) {
                    isProcessingElse = false;
                }
            }
        });

        return functionCalls;
    } catch (error) {
        console.error('Error parsing code:', error);
        return [];
    }
}

// 生成完整条件链(从根到当前节点)
function getFullConditionChain(node) {
    const path = [];
    let current = node;
    while (current && current.condition !== null) {
        path.unshift(current.condition);
        current = current.parent;
    }
    return path.join(' 并且 ');
}

// 优化后的条件处理
function processCondition(testNode, variableMap) {
    return escodegen.generate(testNode)
        .replace(/\b\w+\b/g, m => variableMap[m] || m)
        .replace(/>=/g, '≥')
        .replace(/<=/g, '≤')
        .replace(/===/g, '等于')
        .replace(/==/g, '等于')
        .replace(/!=/g, '≠')
        .replace(/>/g, '>')
        .replace(/</g, '<')
        .replace(/\|\|/g, ' 或 ')
        .replace(/&&/g, ' 且 ')
        .replace(/!/g, '非');
}

// 测试调用
console.log(analyzeFunctionCalls(`
function foo(a, b) {
    var c = 100
    if(c > a){
        if( a > 200){
            alert(1)
            alert(4)
        }else if(a > 100){
            alert(2)
            if(b > 200){
                alert(5)
            }else{
                alert(6)
            }
            alert(7)
        }else{
            alert(3)
            if(b > 200){
                alert(8)
            }else{
                alert(9)
            }
            alert(10)
        }    
    }
}
`, "DV",["alert"]));

关键改动说明

  1. 新增isProcessingElse状态标记:避免重复处理else分支,明确当前是否处于else分支的处理流程中。
  2. 修正else块的条件引用:直接使用currentConditionNode.condition获取当前else对应的前置if条件,而不是错误的父节点条件。
  3. 调整leave阶段的回溯逻辑:只有离开普通IfStatement且不在else处理状态时才回溯,避免else if分支提前回退上下文。
  4. 统一else if的条件生成逻辑:确保else if的条件是「非前置if条件 + 当前else if条件」的组合,符合逻辑链要求。

修复后的预期输出

运行修改后的代码,你会得到符合预期的条件链:

[
  { call: 'alert(1)', condition: '100>a 并且 a>200' },
  { call: 'alert(4)', condition: '100>a 并且 a>200' },
  { call: 'alert(2)', condition: '100>a 并且 非(a>200) 且 a>100' },
  { call: 'alert(5)', condition: '100>a 并且 非(a>200) 且 a>100 并且 b>200' },
  { call: 'alert(6)', condition: '100>a 并且 非(a>200) 且 a>100 并且 非(b>200)' },
  { call: 'alert(7)', condition: '100>a 并且 非(a>200) 且 a>100' },
  { call: 'alert(3)', condition: '100>a 并且 非(a>200) 且 非(a>100)' },
  { call: 'alert(8)', condition: '100>a 并且 非(a>200) 且 非(a>100) 并且 b>200' },
  { call: 'alert(9)', condition: '100>a 并且 非(a>200) 且 非(a>100) 并且 非(b>200)' },
  { call: 'alert(10)', condition: '100>a 并且 非(a>200) 且 非(a>100)' }
]

备注:内容来源于stack exchange,提问作者noob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 10:48:09