引用:Georg Dotzler, Marius Kamp, Patrick Kreutzer, Michael Philippsen. 2017. More Accurate Recommendations for Method-Level Changes. In Proceedings of 2017 11th Joint Meeting of the European Software Engineering Conference and the ACM SIGSOFT Symposium on the Foundations of Software Engineering, Paderborn, Germany, September 4-8, 2017 (ESEC/FSE’17), 11 pages.https://doi.org/10.1145/3106237.3106276
摘要
在大型软件项目的生命周期中,开发人员经常将相同的代码做很小的改动后应用到不同的代码位置。但是这种操作非常耗时且容易出错,因此出现了许多从输入示例中学习更改模式、搜索可能的模式并生成相应推荐的工具。在许多情况下,由于输入示例中的代码移动,生成的推荐在语法或语义上是错误的。因此,它们的准确性很低,如果不进行调整,开发人员不能直接将它们复制到他们的项目中。
我们提出的精确推荐系统(ARES)比其他工具具有更高的准确性,因为它的算法在创建模式和推荐时考虑到了代码移动的影响。对于开发人员在提交源代码归档时手动执行的代码更改,ARES的推荐的准确率达到 96%,并且ARES实现了与其他工具相当的精度和召回率。
1. 介绍
开发人员经常执行容易出错和重复的任务,即对代码库中的许多位置应用相同的系统编辑。造成这种系统性变化的原因各不相同。它们包括错误修复、调用站点对新API的适应性等,并构成软件项目中的大多数结构化编辑。
目前的研究工具是从一个或多个人工提供的训练示例中学习系统编辑,并从中构建通用的模式。然后,这些工具在代码库中搜索要将这些模式应用到的位置,并将应用模式的代码作为建议提供给开发人员。由于这些工具(在很大程度上)纯粹从语法上构造建议的代码,因此代码通常是错误的(使用未定义的变量、调用不存在的函数、遗漏语句等)。因此,推荐的代码通常是不准确的。虽然这些不准确的建议同样有助于识别代码更改的损失,但是开发人员仍然需要手动调整它们,然后才能将它们插入到项目中。
图1是一个代码推荐的例子,LASE[1]和ARSE都会从图1(a,b)两个代码变更中学习其中的更改模式。由于LASE只应用在训练示例中出现的代码转换的公共子集, 因此在图1(d)的修改中保留了assert语句(因为这个语句不是图a和b的公共子集)。并且LASE也不能准确的表达代码移动,如图中所示没有将foo.run()移动到if语句中,这是错误的,因为从开发人员的角度来看,someMethod和下面一行中的代码都应该被移动到新的if语句中。ARES生成的图1(e)中更精确的表达开发者的意图。
为了避免这两个不精确的推荐,ARES的模式表示可以表达输入代码变化和代码运动的变化。ARES还使用能够基于这些模式生成更准确建议的算法。
图2为ARES的工作流程。上排可以得到一个有关所有代码更改的通用模式(模式设计)。该循环从输入集中的代码更改和生成的通用模式开始,并为它们生成一个新的模式(模式创建)。后续迭代通过依次考虑下一个代码更改实例来细化此模式(输入流的确定)。ARES会浏览给定的代码库通过使用通用模式查找该模式适用的位置(应用程序搜索)。然后将模式中编码的转换应用于每个找到位置的副本(推荐创建),并将转换后的副本作为建议呈现给用户。
2. 模式设计
ARES使用接近源代码的模式表示。该模式中有两个普通的Java代码块,一个原始代码块表示转换前的输入示例,另一个经过修改的代码块表示转换后的示例。
ARSE提供了两种泛化模式的方法:1.match注释,当ARES创建一个推荐时,它会在相应的代码位置用实际的变量名替换k;2.wildcard注释,它匹配搜索适当代码位置期间的任意代码。有两个不同的版本。首先,标记为stmt的通配符在代码位置接受none或任意语句。其次,带有expr标记的通配符指定它的哪个部分可以包含任意表达式。
3. 确定输入流
在构建广义模式时,ARES在图2上半部分所示的循环中会一个接一个的输入。ARES使用它们的顺序会影响模式。两个差异很大的变化(可能会导致模式过度泛化,过度使用通配符来隐藏差异)。生成的模式过于一般化会导致在代码库的许多位置都会成功匹配。两个更改之间的编辑距离越小,ARES隐藏在通配符中的不同代码片段就越小。因此,关键的思想是,在循环的每一个迭代阶段,ARES首先识别尽可能接近当前通用模式的代码更改。最初,在第一次迭代中,当没有可用的通用模式时,ARES会选择尽可能接近输入集中所有其他更改的两个代码更改。
为了确定编辑距离,ARES使用一种树形差分算法MTDIFF[2]提取两个抽象语法树(AST)之间的差异。MTDIFF算法可以生成编辑距离,从而更好地捕获两个输入示例的紧密程度。下图为两个代码变化的编辑距离,c包含了一个原始代码块o以及与他对应的修改代码块m,c1和c2的编辑距离为o1和o2的编辑距离加上m1和m2的编辑距离。
4. 模式创建
模式创建步骤的输入是两个代码更改c1(o1,m1)和c2(o2,m2)。图4显示了本节的运行示例,ARES从中创建图3中的模式。
模式创建步骤在原始方法体o1和o2不同的地方添加Wildcard注释,在m1和m2不同的地方添加了Use注释。为此,ARSE使用树差分算法MTDIFF,将原始AST和修改后的AST分别作为输入,将原始AST节点与修改后AST节点进行匹配,如果两个节点类型相同,则可能匹配。MTDIFF使用启发式来匹配节点。基于节点匹配,MTDIFF生成一个小的变更过程脚本(将原始AST转换为修改后的AST的变更操作列表)。
任何属于这种编辑操作的AST节点都可以识别模式创建所使用的带有注释的方法体之间的变化。它还保持模式中所有剩余代码不变,以提高准确性。
下面我们将详细展示ARES如何使用MTDIFF提供的代码变更脚本D(o1,o2)和D(m1,m2)来创建模式。要确定使用注释中的正确名称,ARES还需要变更脚本D(o1,m1)和D(o2,m2)。由于这个过程是ARES最复杂的部分,我们将它分为六个步骤。
- 改变隔离: 当ARES从输入示例生成模式时,它必须确保编辑脚本只覆盖包含实际更改的代码部分。与更改无关但在输入示例中仍然不同的周围代码不应该是模式的一部分。如果没有更改隔离,这些周围的代码将导致模式过度一般化,从而导致推荐不准确。
- 变更脚本调整:更改隔离避免了过度泛化,而编辑脚本调整则在过度泛化和过度拟合之间找到了平衡。为了保持平衡,ARES使用了一个基于规则的系统,其中包含超过50条规则(Github上的规则描述:https://github.com/FAU-Inf2/ARES)
- Match注释插入:该步骤将Match注释插入到通用模式中(见图3),该注释的主要目的是提供o1和o2之间不同的标识符名称列表。
- Wildcard和Use注释插入:这一步根据前面步骤之后剩下的编辑操作将Wildcard和Use注释添加到模式中。
- Wildcard 名字进行赋值:此步骤指定将原始部分中的Wildcard注释链接到修改部分中的Use注释的名称。由于这些名称可以出现在模式两边的不同位置,所以他们可以表示出代码移动的含义。因次它们对推荐的准确性是至关重要。
- Choice注释插入:为了提高建议的准确性,最后一步处理代码更改中与原始部分中的代码不对应的修改部分之间的差异。
5. 应用程序搜索
为了获得较高的准确性,算法必须识别模式中的AST节点(包括通配符)和代码位置上的AST节点之间的正确匹配。为了使算法尽可能快,本节不再依赖于树结构,而是使用AST节点的序列化列表进行代码搜索。
6. 推荐创建
创建步骤的总体构想是使用MTDIFF创建编辑操作的列表,将模式的原始部分更改为修改的部分并将这些编辑操作应用到代码位置的副本中。
7. 结论
我们提出了一种新的精确推荐系统(ARES),专门研究代码移动以提高代码推荐的准确性。更高的准确性意味着ARES生成的代码建议能够更好地反映开发人员所编写的内容。ARES采用比最先进的模式设计更精确地表达代码移动,从而获得更高的精度结果。与其他工具类似,ARES从源代码培训示例生成这些模式。ARES生成的模式只包含带有一组注释的普通Java代码,因此不是开发人员的黑盒。因此,开发人员可以阅读和手动调整模式。
我们还详细介绍了ARES如何生成、概括和应用这些模式。使用这些技术,ARES在我们的评估中达到 96% 的平均推荐准确率,并优于LASE。执行时间稍长一些,但是对于大型的真实源代码归档文件,执行时间仍然不到两分钟。
为了重现性和进一步的研究,我们开源了ARES、编辑脚本调整的规则、所有的评估输入和结果,包括由ARES生成的可读性很强的模式(https://github.com/FAU-Inf2/ARES)。
8. 参考文献
[1] Na Meng, Miryung Kim, and Kathryn S. McKinley. 2013. LASE: Locating and Applying Systematic Edits by Learning from Examples. In ICSE’13: Intl. Conf. Softw. Eng. San Francisco, CA, 502–511.
[2] Georg Dotzler and Michael Philippsen. 2016. Move-optimized Source Code Tree Differencing. In ASE’16: Intl. Conf. Automated Softw. Eng. Singapore, Singapore, 660–671.
致谢
此文由南京大学软件学院2018级硕士门铎翻译转述。