How to use ast to parse javascript code and find out the execution conditions of specified methods

Issue with Parent Condition Context in Else Block During AST Traversal

I’m working on a JavaScript code analysis tool that traverses the Abstract Syntax Tree (AST) to analyze function calls and their conditions. The goal is to dynamically generate a condition chain for each function call based on nested if, else if, and else statements.

Problem Description

When processing an else block, I’m unable to correctly access the parent condition (parent.condition) to generate the negation of the preceding if condition. This results in incorrect condition chains for function calls inside the else block.

Here’s a simplified version of the code I’m analyzing:

javascript

复制

function foo(a, b) {
    var c = 100;
    if (c > a) {
        if (a > 200) {
            alert(1);
        } else if (a > 100) {
            alert(2);
        } else {
            alert(3); // Condition here is incorrect
        }
    }
}

Expected Output

For the else block (alert(3)), the condition should be:

复制

100 > a 并且 非(a > 200) 且 非(a > 100)

However, the current implementation generates incorrect conditions because the parent condition context is not properly maintained.

Current Implementation

Here’s the relevant part of my code:

javascript

复制

if (
    node.type === 'BlockStatement' &&
    parent.type === 'IfStatement' &&
    parent.alternate === node
) {
    // Attempt to get the parent condition
    const parentCondition = currentConditionContext.parent.condition; // ❌ Fails here
    currentConditionContext = {
        type: 'else',
        condition: `非(${parentCondition})`,
        parent: currentConditionContext.parent.parent, // Incorrect parent reference
        siblingNegation: null
    };
}

Issue

The problem occurs because:

  1. The else block incorrectly skips a level when referencing the parent context (parent.parent).

  2. The parent condition is not accessible due to the incorrect parent reference.

Question

How can I properly maintain the parent condition context for else blocks to generate the correct negation of the preceding if condition?

Desired Solution

I need a way to:

  1. Correctly reference the parent condition context for else blocks.

  2. Generate the negation of the preceding if condition dynamically.

  3. Ensure the condition chain is accurate for nested if-else structures.

Additional Context

  • I’m using esprima for parsing, estraverse for traversal, and escodegen for code generation.

  • The condition chain should support arbitrary levels of nesting.

Here’s the full code for reference:

javascript

复制

// Full code implementation

Any guidance or suggestions would be greatly appreciated!


This question is clear, concise, and provides all the necessary context for someone to understand and help with your issue. You can replace the // Full code implementation comment with your actual code if needed.

this is my code, The following code does not achieve the desired effect

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: [] 
        };

        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);
                        }
                    });
                }

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

                // 处理 else if
                if (
                    node.type === 'IfStatement' &&
                    parent.type === 'IfStatement' &&
                    parent.alternate === node
                ) {
                    // 获取父 if 的条件
                    const parentIfCondition = currentConditionNode.parent.condition;
                    const currentCondition = processCondition(node.test, variableMap);
                    
                    // 创建 else if 节点
                    const newNode = {
                        condition: `非(${parentIfCondition}) 且 ${currentCondition}`,
                        parent: currentConditionNode.parent, // 关键修正:父节点指向原 if 的父级
                        children: []
                    };
                    
                    currentConditionNode.parent.children.push(newNode);
                    currentConditionNode = newNode;
                }

                // 处理 else 块
                if (
                    node.type === 'BlockStatement' &&
                    parent.type === 'IfStatement' &&
                    parent.alternate === node
                ) {
                    // 获取父 if 的条件
                    const parentIfCondition = currentConditionNode.parent.condition;
                    
                    // 创建 else 节点
                    const newNode = {
                        condition: `非(${parentIfCondition})`,
                        parent: currentConditionNode.parent, // 关键修正:父节点指向原 if 的父级
                        children: []
                    };
                    
                    currentConditionNode.parent.children.push(newNode);
                    currentConditionNode = newNode;
                }

                // 收集函数调用
                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) => {
                // 离开 if 语句时回溯到父节点
                if (node.type === 'IfStatement') {
                    currentConditionNode = currentConditionNode.parent;
                }
            }
        });

        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(/bw+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"]));

expected result

[
{ 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)' } // ✅
]

actual result

[
  { 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 > 200) 且 a > 100'
  },
  {
    call: 'alert(5)',
    condition: '100 > a 并且 a > 200 并且 非(a > 200) 且 a > 100 并且 b > 200'
  },
  {
    call: 'alert(6)',
    condition: '100 > a 并且 a > 200 并且 非(a > 200) 且 a > 100 并且 非(非(a > 200) 且 a > 100)'
  },
  {
    call: 'alert(7)',
    condition: '100 > a 并且 a > 200 并且 非(a > 200) 且 a > 100'
  },
  { call: 'alert(3)', condition: '100 > a 并且 a > 200 并且 非(a > 200)' },
  {
    call: 'alert(8)',
    condition: '100 > a 并且 a > 200 并且 非(a > 200) 并且 b > 200'
  },
  {
    call: 'alert(9)',
    condition: '100 > a 并且 a > 200 并且 非(a > 200) 并且 非(非(a > 200))'
  },
  { call: 'alert(10)', condition: '100 > a 并且 a > 200 并且 非(a > 200)' }
]

Is there a god to help me

thank you