如何检查两个Java类在语义上是否相同



我需要合并两个类似的巨大项目(1000多个类(。第二个是第一个的分支,它包含了一些特定于国家的行为。这两个项目差异很大,因为svn版本控制处理得很差。

通常情况下,两个类在语义上是相同的。它们的源代码只在警告、导入语句、某些方法或变量的顺序、代码格式、注释等方面有所不同。

有没有一种方法可以自动检查两个类在语义上是否相同?

您应该考虑使用像Soot这样的程序分析工具。Soot有一些优秀的API来分析最适合您目的的代码。例如,要检查两个类是否"语义相同",可以考虑(1(两个类的字段是否相同(或相似((2(两个类同有方法。

字段在Soot中表示为SootField。您将在SootField对象中获得所有必要的信息,以便进行比较。要检查两种方法的语义相似性,可以检查它们的控制流图(CFG(是否相似(详细信息见本指南第5.7节(。

关于如何使用烟灰的提示。

如果您的源目录是srcDir,Java Home是javaHome,类列表是classNames,那么您可以使用以下代码段以编程方式在Soot工具集中加载类。

String sootClassPath = srcDir + ":" 
+ javaHome + "/jre/lib/rt.jar:"
+javaHome + "/jre/lib/jce.jar";
Options.v().set_output_format(Options.output_format_jimple);
Options.v().set_src_prec(Options.src_prec_java);
for (String className : classNames) { // // "className" is like a.b.Myclass
Options.v().classes().add(className);
}
Options.v().set_keep_line_number(true);
Options.v().set_allow_phantom_refs(true);
Scene.v().setSootClassPath(sootClassPath);
Scene.v().loadBasicClasses();

当你的类被加载时,你可以访问如下的类:

SootClass sClass = Scene.v().loadClassAndSupport(className); // "className" is like a.b.Myclass

现在您可以访问sClass的字段和方法,如下所示:

Chain<SootField> fieldList =  sClass.getFields(); // import soot.util.Chain;
List<SootMethod> methods = sClass.getMethods();

你可以迭代一个方法的CFG,如下所示,以获得它的指令列表,

if (method.isConcrete()) {
List<Unit> instructionList = new ArrayList<>();
Body b = method.retrieveActiveBody();
DirectedGraph g = new ExceptionalUnitGraph(b);
Iterator gitr = g.iterator();
while (gitr.hasNext()) {
Unit unit = (Unit) gitr.next();
instructionList.add(unit);
}
}

也许首先使用Architexa这样的工具将两个项目的代码转换为UML图。这可能有助于在系统目标的上下文中识别类的真正功能。然后可以详细比较可疑的等效类。

最新更新