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

时间:2018-07-18 21:49:48

标签: java merge versioning

我需要合并两个类似的大型项目(超过1000个类)。第二个是第一个的分支,它包含一些特定于国家/地区的行为。这两个项目相去甚远,因为svn版本控制非常差。

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

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

2 个答案:

答案 0 :(得分:3)

您应该考虑使用诸如Soot之类的程序分析工具。 Soot具有一些出色的API,可以分析最适合您目的的代码。例如,要检查两个类是否“语义上完全相同”,可以考虑(1)两个类是否具有相同(或相似的字段)(2)两个类都具有相同(或相似的方法)。

字段在Soot中表示为SootField。您将在SootField对象中拥有所有必要的信息,以用于比较。要检查两种方法的语义相似性,可以检查它们的控制流程图(CFGs)是否相似(详细信息在this guide的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);
     }
  }

答案 1 :(得分:0)

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