我必须重构并维护一堆看起来很糟糕的Java类。许多人都有以下实施模式
class Machine {
public int advance(int state) {
switch(state) {
case 7: return step_7();
case 13: return step_13();
case 4: return step_4();
}
}
private int step_7() {
if(something) return 13; else return 4;
}
private int step_13() {
...
return 4;
}
private int step_4() {
if(miep) return 7;
...
return 13;
}
}
从此我想生成一个图形(使用Graphviz和dot
) - 一种“静态调用图”,但不完全是。
除了使用Perl或Python自己解析Java代码之外,我在这里游戏如何自动执行此操作。
我真正想要的是拥有一个抽象语法树(AST)或类似我可以浏览的类,同时打印dot
- 代码。
gprof
来介意)。答案 0 :(得分:6)
有各种各样的Java解析器可以生成AST:
但在处理真正的计算机语言时,AST几乎还不够。例如,要确定调用站点可以调用哪些方法,您需要全名和类型解析,以便您可以准确地确定成千上万个 foo foo 可能会调用位于源文件中的。由于其复杂的查找规则,这对于Java来说并不容易计算。有关此主题的更多详细信息,请参阅我在Life After Parsing上的文章。除非您不关心答案的准确性,否则您不太可能通过简单地使用Python或Perl来复制这些功能。 Eclipse JDT可能具有名称解析;我不确定。 ANTLR Java解析器没有;他们只是解析。
DMS的Java前端具有Java的全名和类型解析。要静态确定您的调用图,您基本上需要进行points-to分析;包含任何类型对象的每个字段本质上都是一个指针,并且您想知道每个指针,特别是它可能选择哪些对象,然后您需要构建一个(全局)调用图来获取所需的基本信息。 DMS为计算各种control and data flow analysis提供支持; Java前端提供基本的流程事实,它将计算本地数据流分析。要获得分数分析,您必须使用DMS的帮助汇总这些事实,然后构建该调用图。对于Java,我们不会使用DMS,但是我们已经大规模地使用C(一个系统中有2600万行),而Java的模拟将非常相似并且使用大多数相同的DMS机制;一旦进行了点分析,调用图构造就相当容易了。我们已经导出了像DOT图这样的图形;你需要过滤它们以获得DOT实际上可以渲染的子图。
您可以从类二进制分析文件(例如Wala)收集流分析事实。您仍将面临构建点分析和全局调用图的问题。我记得Wala在这里有一些帮助,但我不记得是什么了。
您也许可以使用profiler tool收集动态构造的调用图。除非您在分析过程中仔细运用所有系统功能,否则这样的调用图可能非常不完整;这很难做到。
最终,您可能想要更改代码。也许您想要内联 stepN 函数。也许你想手工完成它,但如果你的代码充满了这些东西,也许你想要自动化。像DMS这样的工具提供了源到源的转换,实现了这种自动代码更改。 Wala在这里不会帮助你。