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

使用ANTLR4解析Java文件时如何存储方法名及其内部调用的方法名

问题根源

你当前代码的核心问题是共用了全局唯一的HashSet<String> methodCallNames实例,所有方法调用收集的结果都存在同一个集合里,存入HashMap时也只是存了这个集合的引用,自然每个方法对应的调用都是整个文件的全量数据。

可行方案

方案1:基于监听器+栈实现(最推荐,无需自定义遍历逻辑)

ANTLR的监听器触发顺序是深度优先的:进入方法节点→遍历所有子节点(包括内部的方法调用节点)→退出方法节点,我们可以用栈存储当前正在解析的方法的调用集合,完全依托ANTLR原生遍历逻辑实现需求:

private HashMap<String, HashSet<String>> methodCalls = new HashMap<>();
// 用栈存储当前作用域的方法调用集合
private Stack<HashSet<String>> callStack = new Stack<>();

// 进入方法声明时压入新的空集合
@Override
public void enterMethodDeclaration(Java9Parser.MethodDeclarationContext ctx) {
    callStack.push(new HashSet<>());
}

@Override
public void exitMethodDeclaration(Java9Parser.MethodDeclarationContext ctx) {
    String methodName = ctx.methodHeader().methodDeclarator().identifier().getText();
    // 退出方法时弹出栈顶的当前方法调用集合,存入map
    methodCalls.put(methodName, callStack.pop());
}

@Override
public void exitMethodInvocation(Java9Parser.MethodInvocationContext ctx) {
    try {
        String m = ctx.methodName().identifier().getText();
        // 直接往栈顶的当前方法集合里加,加判空避免类内部非方法作用域的调用被误统计
        if (!callStack.isEmpty()) {
            callStack.peek().add(m);
        }
    } catch (Exception e) {
        // 可按需添加异常日志
    }
}

方案2:基于访问者模式直接遍历子树

如果你希望在同一个方法内完成方法名+内部调用的收集,可以改用访问者模式,访问方法声明节点时主动遍历当前节点的所有子节点提取方法调用:

private HashMap<String, HashSet<String>> methodCalls = new HashMap<>();

@Override
public Void visitMethodDeclaration(Java9Parser.MethodDeclarationContext ctx) {
    String methodName = ctx.methodHeader().methodDeclarator().identifier().getText();
    HashSet<String> callNames = new HashSet<>();
    // 递归遍历当前方法节点的所有子节点,筛选方法调用节点
    collectMethodCalls(ctx, callNames);
    methodCalls.put(methodName, callNames);
    return super.visitMethodDeclaration(ctx);
}

private void collectMethodCalls(ParseTree node, HashSet<String> callNames) {
    if (node instanceof Java9Parser.MethodInvocationContext) {
        try {
            callNames.add(((Java9Parser.MethodInvocationContext) node).methodName().identifier().getText());
        } catch (Exception ignored) {}
        return;
    }
    for (int i = 0; i < node.getChildCount(); i++) {
        collectMethodCalls(node.getChild(i), callNames);
    }
}

内容的提问来源于stack exchange,提问作者Mia

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 02:36:03