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"]));
关键改动说明
- 新增
isProcessingElse状态标记:避免重复处理else分支,明确当前是否处于else分支的处理流程中。 - 修正else块的条件引用:直接使用
currentConditionNode.condition获取当前else对应的前置if条件,而不是错误的父节点条件。 - 调整leave阶段的回溯逻辑:只有离开普通IfStatement且不在else处理状态时才回溯,避免else if分支提前回退上下文。
- 统一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
相关产品推荐
相关产品推荐

