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

agd*_*v84 9 java versioning merge

我需要合并两个类似的巨大项目(1000多个类).第二个是第一个的分支,它包含一些特定于国家的行为.这两个项目分歧很大,因为svn版本处理得非常糟糕.

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

有没有办法自动检查两个类在语义上是否相同?

Saz*_*man 3

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

场以烟灰形式表示SootFieldSootField您将在要用于比较的对象中拥有所有必要的信息。要检查两种方法的语义相似性,您可以检查它们的控制流图(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();
Run Code Online (Sandbox Code Playgroud)

加载类后,您可以访问如下所示的类:

 SootClass sClass = Scene.v().loadClassAndSupport(className); // "className" is like a.b.Myclass
Run Code Online (Sandbox Code Playgroud)

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

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

你可以迭代一个方法的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);
     }
  }
Run Code Online (Sandbox Code Playgroud)