如何检查两个 Java 类在语义上是不是相同?
Posted
技术标签:
【中文标题】如何检查两个 Java 类在语义上是不是相同?【英文标题】:How can I check if two Java classes are semantically identical?如何检查两个 Java 类在语义上是否相同? 【发布时间】:2018-12-26 22:22:51 【问题描述】:我需要合并两个类似的大型项目(1000 多个课程)。第二个是第一个的分支,它包含一些特定于国家/地区的行为。这两个项目分歧很大,因为 svn 版本控制处理得非常糟糕。
经常发生两个类在语义上相同的情况。它们的源代码仅在警告、导入语句、某些方法或变量的顺序、代码格式、cmets 等方面有所不同。
有没有办法自动检查两个类在语义上是否相同?
【问题讨论】:
反射:getFields
和 getMethods
检查字节码,即使用一些字节码库读取.class
文件并进行比较。如果字节码是等价的,那么这些类是“语义相同的”。
Git diff?? ........
@SamOrozco 这还不够——你可以有相同的方法,但实现不同的事情。
我会成对解析这些项目中的 Java 文件,并根据您定义的规则比较 AST。然后检查比较结果,调整规则,重复。但这可能非常困难。
【参考方案1】:
您应该考虑使用Soot 等程序分析工具。 Soot 有一些优秀的 API 可以分析最适合您目的的代码。例如,要检查两个类是否“语义相同”,您可以考虑(1)两个类是否具有相同(或相似的字段)(2)两个类是否具有相同(或相似的方法)。
字段在 Soot 中表示为 SootField
。您将在要用于比较的 SootField
对象中拥有所有必要的信息。要检查两种方法的语义相似性,您可以检查它们的控制流图 (CFGs) 是否相似(详细信息在 this guide 的第 5.7 节中)。
关于如何使用烟灰的提示。
如果您的源目录是srcDir
,Java Home 是javaHome
,类列表是classNames
,那么您可以使用以下代码 sn-p 以编程方式在 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);
【讨论】:
非常有趣的库和解决方案。我会尽快测试它。非常感谢。【参考方案2】:也许首先使用 Architexa 之类的工具将 2 个项目的代码转换为 UML 图。 这可能有助于在系统目标的上下文中识别类的真正功能。 然后可以详细比较可疑的等效类。
【讨论】:
以上是关于如何检查两个 Java 类在语义上是不是相同?的主要内容,如果未能解决你的问题,请参考以下文章