我需要合并两个类似的大型项目(超过1000个类)。第二个是第一个的分支,它包含一些特定于国家/地区的行为。这两个项目相去甚远,因为svn版本控制非常差。
经常会发生两个类在语义上相同的情况。它们的源代码仅在警告,导入语句,某些方法或变量的顺序,代码格式,注释等方面有所不同。
有没有一种方法可以自动检查两个类在语义上是否相同?
答案 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图。 这可能有助于在系统目标的上下文中识别类的实际功能。 然后可以对可疑的等效类进行详细比较。