Fine-grained and Accurate Source Code Differencing

HAL

archives-ouverter.fr

HAL是一个多学科开放存取档案馆,用于存放和传播科学研究文件,无论其是否出版。这些文件可能来自法国或国外的教学和研究机构,或者来自公共或私人研究中心。

细粒度和准确的源代码差异

Jean-Rémy Falleri, Floréal Morandat, Xavier Blanc, Matias Martinez, Martin Monperrus

引用这个版本

Jean-Rémy Falleri, Floréal Morandat, Xavier Blanc, Matias Martinez, Martin Monperrus. Fine-grained and Accurate Source Code Differencing. Proceedings of the International Conference on Automated Software Engineering, 2014, Västeras, Sweden. pp.313-324, 2014, <10.1145/2642937.2642982>.

HAL Id

hal-01054552

https://hal.archives-ouvertes.fr/hal-01054552

2014年9月12日提交

细粒度和准确的源代码差异

作者

  1. Jean-Rémy

    Falleri Univ. Bordeaux, LaBRI, UMR 5800 F-33400, T alence, France

    falleri@labri.fr

  2. Floréal Morandat

    Univ. Bordeaux, LaBRI, UMR 5800 F-33400, T alence, France

    fmoranda@labri.fr

  3. Xavier Blanc

    Univ. Bordeaux, LaBRI, UMR 5800 F-33400, T alence, France

    xblanc@labri.fr

  4. Matias Martinez

    INRIA and University of Lille, France

    matias.martinez@inria.fr

  5. Martin Monperrus

    INRIA and University of Lille, France

    martin.monperrus@inria.fr

允许制作本作品的全部或部分的数字或硬拷贝供个人或课堂使用,但不收取任何费用,前提是复制品的制作或分发不是为了盈利或商业利益,并且复制品的第一页上有本通知和完整引用。必须尊重作者以外的其他人对本作品组成部分的版权。允许有信用的提取。以其他方式复制或重新发布、在服务器上发布或重新发布到列表,需要事先获得特定许可和/或付费。请求来自的权限permissions@acm.org。

2014年9月15日至19日,瑞典阿斯特拉斯。

版权归作者所有。授权给ACM的出版权。

ACM 978-1-4503-3013-8/14/09…$15.00。

http://dx.doi.org/10.1145/2642937.2642982。

摘要

软件演化核心是对源代码文件进行的一系列编辑操作,称为编辑脚本。由于软件系统逐版本存储的,因此必须根据这些版本计算编辑脚本,这是一项复杂的任务。现有方法通常只使用添加行和删除行操作来计算文本粒度的编辑脚本。然而,从这样的编辑脚本推断语法变化是很困难的。由于移动代码是编辑代码时经常执行的操作,因此也应考虑到这一点。在本文中,我们通过引入一种算法来解决这些问题,该算法在抽象语法树粒度(包括移动操作)下计算编辑脚本。我们的目标是计算简短且接近原始开发人员意图的编辑脚本。我们的算法是在一个自由可用且可扩展的工具中实现的,该工具已经过深入验证。

类别和主题描述符

D.2.3[软件工程]: 编码工具和技术

通用术语

算法、实验

关键词

软件演化,程序理解,树差异,AST。

1 简介

软件演化的第一定律指出,几乎所有的软件系统都必须演化才能令人满意[19]。自从该定律制定以来,已经进行了许多研究,以更好地理解软件系统是如何演化的,并形成了所谓的软件演化研究领域[21]。

==存在全局软件演化(例如需求、执行环境的演化……)和本地软件演化(源代码文件的演化)。====在本文中,我们关注后者,即理解源代码文件是如何演变的。特别是,我们关注编辑脚本,它是对源代码文件进行的编辑操作的序列。==通常,由于软件存储在版本控制系统中,所以编辑脚本是在同一文件的两个版本之间计算的。编辑脚本的目标是准确反映对文件执行的实际更改。

开发人员每天都会使用编辑脚本。例如,Unix diff工具将源代码文件的两个版本作为输入,以文本行粒度执行Myers算法[24],并返回一个编辑脚本,指示添加或删除了哪些行。然而,diff的局限性是双重的。首先,它只计算添加和删除,而不考虑其他类型的编辑操作,如更新和移动。其次,它的粒度(文本行)粗粒度的,与**源代码结构(抽象语法树)**不一致。

为了克服这一主要限制,有一些算法可以在抽象语法树(AST)级别工作[13]。使用AST粒度主要优点是编辑脚本直接引用代码的结构。例如,如果一个编辑动作是添加一个新的功能节点,那么这显然意味着代码中添加了一个新功能。尽管有一些关键贡献(例如[13]),计算AST编辑脚本的问题仍然存在,主要有两个挑战:处理移动操作,以及扩展到具有数千个节点1细粒度AST。这就是本文的贡献所在。

1具有添加、删除和更新操作的最著名算法的时间复杂度为 O ( n 3 ) O(n^3) O(n3),其中 n n n是AST的节点数[27]。计算可以包括移动节点操作的最小编辑脚本,已知是NP-难问题[4]

==为了设计我们的新算法,我们采用开发者的观点:她对理论上的最短编辑脚本从不感兴趣。她很想拥有一个能很好地反映实际变化的编辑脚本。==因此,我们的目标不是在两个版本之间找到最短的操作序列,而是一个能够很好地反映开发人员意图的序列因此,我们设计了一种基于启发式的算法该算法包含关于什么是好的编辑脚本实用规则,同样重要的是,这是高效的,可以扩展到大型AST此算法已在一个免费可用和可扩展的工具2实现

2github.com/jrfaller/gumtree

总之,我们的贡献是:

  • 考虑移动动作新型高效AST差异算法及其实现
  • 根据真实数据自动评估实施绩效
  • 通过对144个不同场景手动评估,对算法的结果进行手动评估
  • 12792个差异场景大规模自动评估表明,我们算法的结果比相关工作更准确,即使是在细粒度AST上也是如此。

本文的其余部分结构如下:第2节介绍了什么是AST差异。第3节介绍了我们新的AST差异算法。第4节介绍了我们实现这个新算法的工具及其性能。第5节对我们的工具进行了实证评估。第6节介绍了相关工作。最后,第7节总结并介绍了未来的工作

2 AST差异

在介绍AST差异之前,我们简要介绍了定义AST结构的主要概念。我们认为AST是一个带标记有序有根树,其中节点可能有一个字符串值节点的标签对应于语法中生成规则的名称,即它们对结构进行编码节点的值对应于代码中的实际标记

更正式地说,让 T T T成为AST T T T是一组节点 T T T有一个节点是(由 r o o t ( T ) root(T) root(T)表示)。每个节点 t ∈ T t∈T tT有一个父级 p ∈ T ∪ ∅ p∈T∪∅ pT。根是唯一具有 ∅ ∅ 父级的结点。节点的父节点 p a r e n t ( t ) parent(t) parent(t)表示。每个节点 t ∈ T t∈T tT有一个子序列 c h i l d r e n ( t ) children(t) children(t))。每个节点都有字母表 l ∈ ∑ ( l a b e l ( t ) = l ) l∈∑(label(t)=l) l(label(t)=l)中的标签。每个节点都有一个可能为空的字符串值 v ∈ S t r i n g v∈String vString v a l u e ( t ) = v ∨ ϵ value(t)=v∨\epsilon value(t)=vϵ)。

==作为示例,我们考虑一个简单的Java源代码其对应的AST参见图1的左下角)。==此Java源代码的AST包含19个节点,对应于Java编程语言的结构。因此,AST的每个节点都有一个标签该标签映射到源代码的结构元素(如MethodDeclarationNumberLiteral),以及一个对应于代码中实际标记的值(如与1关联的NumberLiteral)。有些值不编码信息,因此被丢弃,例如MethodDeclaration没有与之关联的有趣标记,因此没有值。

在这里插入图片描述

图1:两个示例Java文件及其相应的AST和映射。仅具有标签的节点表示为:Label,具有标签和值的节点表示:Lable: value自顶向下阶段的映射长虚线表示(这些节点的后代也被映射,但为了增强可读性,省略了它)。自底向上阶段的映射使用**短虚线(容器映射)交替虚线(恢复映射)**进行描述。不匹配的节点呈灰色。

==AST可以具有不同的粒度,一个节点可以编码整个指令更精细的粒度表达式。==我们相信细粒度的AST最适合开发人员。例如,return "Foo!";语句,可以用类型为Statement和值return "Foo!"的单个节点进行编码,或者像我们的示例中那样使用两个节点(参见节点b)。如果此语句更改为return "Foo!" + i;,只有细粒度表示才能看到添加了InfixExpression:+SimpleName:i节点。

AST差异基于AST编辑操作的概念。==它旨在计算将AST转换为另一个AST的一系列编辑操作。此序列称为编辑脚本。==关于AST的定义,我们考虑以下编辑操作

  • u p d a t e V a l u e ( t , v n ) updateValue(t,v_n) updateValue(t,vn) t t t的旧值替换为新值 v n v_n vn
  • a d d ( t , t p , i , l , v ) add(t,t_p,i,l,v) add(t,tp,i,l,v)在AST中添加一个新节点 t t t。如果 t p t_p tp不为空并且指定了 i i i,则 t t t t p t_p tp的第 i i i个子节点。否则 t t t是新的根节点,并将前一个根节点作为其唯一的子节点。最后, l l l t t t的标签, v v v t t t的值。
  • d e l e t e ( t ) delete(t) delete(t)删除AST的叶节点。
  • m o v e ( t , t p , i ) move(t,t_p,i) move(t,tp,i)移动节点 t t t并使其成为 t p t_p tp的第 i i i个子节点。请注意, t t t的所有子级也会移动,因此此操作会移动整个子树。

==由于有许多可能的编辑脚本执行相同的转换,因此编辑脚本的质量取决于其长度:转换越短,质量越好。==注意,当考虑移动动作时,找到最短变换是NP困难的。

然后,我们在本文中考虑AST差异问题输入两个AST目的是识别编辑动作(包括move)的短编辑脚本 σ σ σ,该脚本将第一个AST(名为 t 1 t_1 t1)转换为第二个AST(名为 t 2 t_2 t2)。执行这种AST差异的现有算法使用试探法返回短编辑脚本 σ σ σ。此外,它们通常遵循两个步骤的过程。首先,它们在两个AST的相似节点之间建立映射(节点对)。==这些映射有两个约束:一个给定的节点只能属于一个映射,而映射涉及具有相同标签的两个节点。其次,基于这些映射,他们推断出必须在第一个AST上执行的编辑脚本才能获得第二个AST。==第一步是最关键的一步,因为第二步存在二次优化算法[6,15]。在下一节中,我们将介绍一种计算两个AST之间映射的新算法

3 GumTree算法

==如前一节所述,AST差异算法分为两个步骤建立映射,然后推导编辑脚本。==由于已经为第二步开发了一个最优和二次算法[6],我们在本节中仅解释如何寻找两个AST之间的映射。然后,Chawathe等人[6]的算法可以使用该算法的输出来计算实际的编辑脚本我们计算两个AST之间映射的算法两个连续阶段组成

  1. 一种自顶向下的贪心算法,用于寻找高度递减的同构子树。在这些同构子树的节点之间建立映射。它们被称为锚映射
  2. 一种自底向上的算法,其中两个节点匹配(称为容器映射),前提是它们的后代(节点的子节点,以及它们的子节点等等)包含大量公共锚。当两个节点匹配时,我们最终应用一个优化算法在它们的后代中搜索其他映射(称为恢复映射)。

此算法灵感来自于开发人员手动查看到文件之间的更改的方式。==首先,他们搜索最大的未修改代码。然后他们推断出哪个代码容器可以映射在一起。最后,他们观察了每个容器中剩余物的精确差异。==为了更好地说明我们的算法,我们介绍了图1所示的示例

3.1 自顶向下阶段

GumTree的第一步是自顶向下贪心地搜索 T 1 T_1 T1 T 2 T_2 T2之间的最大同构子树。在解释如何进行之前,我们先介绍树中的高度概念。节点高度 t ∈ T t∈T tT定义为:1)对于叶节点 T T T h e i g h t ( t ) = 1 \mathbf{height}(t)=1 height(t)=1;2)对于内部节点 T T T h e i g h t ( t ) = max ⁡ ( { h e i g h t ( c ) ∣ c ∈ c h i l d r e n ( t ) } ) + 1 \mathbf{height}(t)=\max(\{\mathbf{height}(c)|c∈ children(t)\})+1 height(t)=max({height(c)cchildren(t)})+1该算法使用称为高度索引优先级列表辅助数据结构此列表包含按高度递减顺序排列的节点序列。以下函数与此数据结构关联。 p u s h ( t , l ) push(t,l) push(t,l)节点 t t t插入列表 l l l中。 p e e k M a x ( l ) peekMax(l) peekMax(l)返回列表的最大高度 p o p ( l ) pop(l) pop(l)返回并从 l l l移除高度等于 p e e k M a x ( l ) peekMax(l) peekMax(l) l l l的所有节点的集合 o p e n ( t , l ) open(t,l) open(t,l) t t t的所有子代插入 l l l中。我们还定义了dice函数该函数测量给定一组映射 M \mathcal M M两个节点之间的公共后代的比率,即 d i c e ( t 1 , t 2 , M ) = 2 × ∣ t 1 ∈ s ( t 1 ) ∣ ( t 1 , t 2 ) ∈ M ∣ s ( t 1 ) ∣ + ∣ s ( t 2 ) ∣ dice(t_1,t_2,\mathcal M)=\frac{2×|{t_1∈s(t_1)|(t_1,t_2)∈\mathcal M}}{|s(t_1)|+|s(t_2)|} dice(t1,t2,M)=s(t1)+s(t2)2×t1s(t1)(t1t2)M,其中 s ( t i ) s(t_i) s(ti)节点 t i t_i ti后代集合dice系数范围 [ 0 , 1 ] [0,1] [0,1]实数区间内,值为1表示 t 1 t_1 t1后代集合 t 2 t_2 t2后代集合相同。GumTree自顶向下阶段的算法算法1所示。

在这里插入图片描述

在该算法中,我们将 T 1 T_1 T1 T 2 T_2 T2公共子树映射为可能的最大高度原则是从根开始(因为它们有最大的高度)并检查它们是否同构。如果没有,他们的子节点就会接受测试。一旦在另一棵树中找到同构节点,就会匹配一个节点。当一个给定的节点可以与多个节点匹配时,所有潜在的映射都保存在一个专用的候选映射列表中。该列表在处理完唯一匹配的所有节点之后进行处理;这些节点被直接放置到映射集中。该算法只考虑高度大于 m i n H e i g h t minHeight minHeight的节点。为了处理候选映射,我们在每个候选映射的父级上使用dice函数。此函数的值用于对候选映射列表进行排序,具有较大值的映射优先。然后,直到候选映射列表为空,我们移除第一个元素,将其添加到映射集中,然后从候选映射列表中移除涉及此映射的节点的映射。在图1中 m i n H e i g h t = 2 minHeight=2 minHeight2的示例树上,算法1找到了虚线所示的映射。

3.2 自底向上阶段

算法2显示了自底向上阶段自顶向下阶段产生的映射被作为输入。首先,我们寻找容器映射,这是在两个节点具有大量匹配的子节点时建立的。==对于找到的每个容器映射,我们都会查找恢复映射,这些映射在映射节点的仍然不匹配的后代中进行搜索。==为了找到容器映射 T 1 T_1 T1节点后序处理。对于 T 1 T_1 T1每个不匹配的非叶节点,我们从 T 2 T_2 T2中提取候选节点列表。一个节点 c ∈ T 2 c∈T_2 cT2如果满足 l a b e l ( t 1 ) = l a b e l ( c ) label(t_1)=label(c) label(t1)label(c) c c c不匹配,并且 t 1 t_1 t1 c c c有一些匹配的后代,则它是 t 1 t_1 t1候选。然后我们选择具有最大 d i c e ( t 1 , t 2 , M ) \mathbf{dice}(t_1,t_2,\mathcal M) dice(t1,t2,M)值的候选 t 2 ∈ T 2 t_2∈T_2 t2T2。如果 d i c e ( t 1 , t 2 , M ) > m i n D i c e \mathbf{dice}(t_1,t_2,\mathcal M)>minDice dice(t1,t2,M)>minDice t 1 t_1 t1 t 2 t_2 t2匹配在一起。为了搜索 t 1 t_1 t1 t 2 t_2 t2的后代之间的其他映射,我们首先删除它们匹配的后代,如果两个子树的大小都小于 m a x S i z e maxSize maxSize,我们应用一个表示为 o p t opt opt算法该算法可以找到一个没有移动操作的最短编辑脚本。在我们的实现中,我们使用RTED算法[27]。如果从这个编辑脚本中导出的映射涉及具有相同标签的节点,则将其添加到 M \mathcal M M中。

在这里插入图片描述

在图1的示例树上,当 m i n D i c e = 0.2 minDice=0.2 minDice0.2时,算法2使用短虚线找到容器映射。在 m a x S i z e = 100 maxSize=100 maxSize100的情况下,从这些容器映射中可以找到几个恢复映射,以交替的行显示。最后,从这些映射生成的编辑脚本如下(节点 a a a b b b c c c如图1所示节点 t i t_i ti新节点):
a d d ( t 1 a , 1 , R e t u r n S t a t e m e n t , ϵ ) a d d ( t 2 , t 1 , 0 , S t r i n g L i t t e r a l , B a r ) a d d ( t 3 , a , 2 , I f S t a t e m e n t , ϵ ) a d d ( t 4 , t 3 , 0 , I n f i x E x p r e s s i o n , = = ) a d d ( t 5 , t 4 , 0 , S i m p l e N a m e , i ) a d d ( t 6 , t 4 , 1 , P r e f i x E x p r e s s i o n , − ) a d d ( t 7 , t 6 , 0 , N u m b e r L i t e r r a l , 1 ) m o v e ( b , t 3 , 1 ) u p d a t e V a l u e ( c , p r i v a t e ) add(t_1a,1,ReturnStatement,\epsilon)\\ add(t_2,t_1,0,StringLitteral,Bar)\\ add(t_3,a,2,IfStatement,\epsilon)\\ add(t_4,t_3,0,InfixExpression,==)\\ add(t_5,t_4,0,SimpleName,i)\\ add(t_6,t_4,1,PrefixExpression,−)\\ add(t_7,t_6,0,NumberLiterral,1)\\ move(b,t_3,1)\\ updateValue(c,private)\\ add(t1a,1,ReturnStatement,ϵ)add(t2,t1,0,StringLitteral,Bar)add(t3,a,2,IfStatement,ϵ)add(t4,t3,0,InfixExpression,==)add(t5,t4,0,SimpleName,i)add(t6,t4,1,PrefixExpression,)add(t7,t6,0,NumberLiterral,1)move(b,t3,1)updateValue(c,private)
我们为算法的三个阈值推荐以下值。我们建议 m i n H e i g h t = 2 minHeight=2 minHeight2,以避免单个标识符在任何地方都匹配 m a x S i z e maxSize maxSize用于算法2恢复部分,可以导致立方复杂的算法。为了避免计算时间过长,我们建议使用 m a x S i z e = 100 maxSize=100 maxSize100。最后,在50%的公共节点下,两个容器节点可能不同。因此,我们建议使用 m i n D i c e = 0.5 minDice=0.5 minDice=0.5

3.3 复杂性分析

==我们的算法具有 O ( n 2 ) O(n^2) O(n2)最坏情况复杂度,其中 n = m a x ( ∣ T 1 ∣ , ∣ T 2 ∣ ) n=max(|T_1|,|T_2|) nmax(T1,T2)。==实际上,算法1最坏的情况下执行具有相同高度的节点笛卡尔积。由于[7]中提出的哈希码,我们使用的同构测试 O ( 1 ) O(1) O(1)内,因此整个算法 O ( n 2 ) O(n^2) O(n2)。此外,对于实际的AST,这种最坏的情况不太可能发生。算法2还在最坏情况下执行不匹配节点笛卡尔积这个操作也是 O ( n 2 ) O(n_2) O(n2),因为所有子操作都是有界的,即使是只应用于小于固定大小的树的三次复杂的算法 o p op opt也是如此。最后,在[6]中描述的从映射计算编辑脚本的算法,在最坏情况下的复杂度也为 O ( n 2 ) O(n^2) O(n2)

4 工具

上一节中描述的算法已经在一个免费的可扩展工具中实现。AST差异需要解析器(产生AST表示)来支持给定的编程语言。这显然是一个限制,因为新的语言无法开箱即用。这种工具面临的另一个有趣的挑战是,它被具有不同期望的不同参与者使用,例如希望编辑脚本的简洁图形显示以快速理解它的开发人员,或希望结果以结构化格式自动处理的研究人员。在本节中,我们将介绍我们的AST差异工具,它允许集成新的编程语言、差异算法和提供结果的方法。

4.1 架构

我们的工具使用如图2所示的管道和过滤器架构。两个输入文件通过一个解析器转换为两个AST。由于解析器是一个抽象模块,因此可以提供几个具体的实现(例如Java或C)。然后将这两个AST提供给一个抽象映射模块,该模块计算一组映射作为输出。由于该模块也是抽象的,因此可以提供几种具体算法(如GumTree或ChangeDistiller[13])。最后,将这组映射提供给计算实际编辑脚本的操作模块。输入文件、AST、映射和编辑脚本最终被提供给抽象输出模块。由于此模块是抽象的,因此可以提供多个输出(例如,XML、JSON等)。注意,所有的数据结构都提供给输出模块;因此它可以对它们中的任何一个进行操作(例如,它可以生成AST或编辑脚本的XML)。

在这里插入图片描述

图2:我们的管道和过滤器架构。抽象模块呈灰色。

使用这种架构,我们已经能够集成Java(使用EclipseJDT解析器)、JavaScript(使用MozillaRhino解析器R(使用FastR解析器[17])和C(使用Coccinelle解析器[26])编程语言。我们还集成了GumTreeChangeDistiller[13]、XYDiff[8]和RTED[27]算法。最后,我们可以生成以下输出:AST的graphviz表示AST的XML表示编辑脚本的基于web的视图如图3所示)以及编辑脚本的XML表示

在这里插入图片描述

图3:我们工具的基于web的差异视图。

4.2 运行性能

在本节中,我们希望评估工具在实际数据上的运行时性能。如前一节所述,我们的工具将差异算法应用于源代码文件的两个版本的AST解析器。我们已经将几个解析器集成到我们的工具中。我们在本节中使用Java和JavaScript解析器。

为了收集有代表性的数据来评估我们的工具,我们任意选择了两个成熟的、流行的和中大型的项目。对于Java语言,我们使用Jenkins(连续集成服务器),对于JavaScript,我们使用JQuery(DOM操作库)。我们任意选择了每个项目的完整版本,并提取了与此版本对应的提交中执行的每个文件修改。在Jenkins中,我们使用1.509.4版本→ 1.532.2,其中我们提取了1144个修饰。在JQuery中,我们使用版本1.8.0→ 1.9.0,其中我们提取了650个修改。每次修改都包含一对文件(上一版本和下一版本)。它们是通过Harmony平台提取出来的[12]。

在这项性能研究中,我们要评估两个重要方面:运行时间和内存消耗。我们使用MacBook Pro视网膜,2.7GHz Intel Core i7,16 Gb RAM。为了获得参考指标,除了我们的工具之外,我们还使用了其他三种工具。我们使用的工具的完整列表是:

  • 一个经典的文本差异工具,它通过在文本行上添加和删除操作来计算编辑脚本。如第6节所述,该工具速度非常快,因此表示代码差异算法的下限。在我们的实验中,我们使用了Google实现3

    3code.google.com/p/google-diff-match-patch

  • GumTree中包含的解析器仅解析修改中涉及的两个文件,而不应用AST差异算法。由于解析文件是执行AST差异的必需品,因此它代表了AST差算法的下限。在我们的实验中,我们使用EclipseJDT解析器来解析Java文件,使用MozillaRhino解析器解析JavaScript文件。

  • GumTree算法(包括解析),具有以下阈值: m i n H e i g h t = 2 minHeight=2 minHeight=2 m i n D i c e = 0.5 minDice=0.5 minDice=0.5 m a x H e i g h t = 100 maxHeight=100 maxHeight=100

  • RTED算法(包括解析),通过添加、更新和删除操作在AST上计算编辑脚本如第6节所述,RTED具有三次最坏情况复杂度( n 3 n^3 n3)。因此,它表示AST差异的上限。在我们的实验中,我们在我们的框架中使用了Pawlik等人4提供的实现。

    4www.inf.unibz.it/dis/projects/tree-edit-distance

我们只将GumTreetext-diffRTED进行比较,因为我们按照文章的描述重新实现了工具中包含的其他算法,但没有特别注意优化。因此,报告这些算法的内存消耗或运行时间是不公平的。

对于内存消耗,我们确保工具扫描使用4Gb RAM运行,这是现代计算机中常见的内存量。在这种程度上,我们使用绑定到4Gb内存的Java虚拟机。我们在每次修改时运行每个工具,并计算导致内存不足错误的修改次数。在这个实验中,唯一出现内存不足错误的工具是RTED,有82个错误(大约5%的修改)。尽管这个数字并不高,但它仍然表明RTED的复杂性在某些情况下会导致非常昂贵的内存消耗。

对于运行时间,我们进行了两个实验。在第一个实验中,我们研究了这些工具是否能够在10秒内计算出修改的编辑脚本。10秒钟后,我们相信开发人员不会交互使用这些工具。在这种情况下,我们在每次修改时运行每个工具,并统计执行持续时间超过10秒的情况。在这个实验中,只有RTED经历了206次这样的情况(大约12%的情况没有内存不足错误)。因此,根据我们的数据,RTED无法计算大约17%的案例的编辑脚本,这是大量案例。它清楚地表明,该算法的复杂性不适合于实际数据。

在第二个实验中,我们比较了工具的运行时间。为了计算运行时间,我们为每次修改计算十次编辑脚本,并保留这些值的中值。为了避免措施中的噪音,我们通过在随机修改上运行每种算法100次来确保Java虚拟机是热的,即,不涉及更多的动态加载,并且JIT编译器已经编译并安装了与热点对应的代码。我们还预加载修改中涉及的所有文件,以避免IO延迟。为了能够比较同一数据集上的工具,我们放弃了导致至少一个工具出现内存不足错误或执行超时(执行时间超过10秒)的所有修改。为了表示这些值,我们使用textdiff的运行时间作为参考值,因为它是现有的更快的工具。因此,对于每次修改,我们将Parsing、GumTree和RTED工具的运行时间除以文本差异工具的运行。此比率表示工具比执行文本差异慢的次数。然后,我们给出了这些结果比率分布的箱线图。

图4显示了第二个实验的结果。第一个有趣的结论是,仅仅解析文件比执行文本差异要长得多:解析时间比率的中值是10。此外,我们看到使用GumTree计算编辑脚本只比仅仅解析文件慢一点(Jenkins的中值是18,JQuery的中值为30)。Jenkins和JQuery中间层之间的差异表明JavaScript AST可能包含比Java AST更多的节点。最后,我们看到RTED比解析文件慢得多(Jenkins的中值为298,JQuery为2654)。RTED工具也观察到两个中值之间的差异。

在这里插入图片描述

图4:工具运行时间比率的分布。对于每个工具,左边的方框图显示Jenkins的比率,右边的方框图则显示JQuery的比率。运行时间比是工具的运行时间除以文本diff的运行时间。它表示它比文本diff慢的次数。

总之,我们清楚地看到,textdiff工具是迄今为止最快的。然而,使用GumTree执行AST差异只会在解析文件时产生少量开销。这意味着我们的算法很快,因此可以应用于实际数据。GumTree的平均运行时间在Jenkins上为20毫秒,在JQuery上为74毫秒。我们的实验还证实,与文本差异相比,在真实数据上使用RTED会带来巨大的开销。

5 评估

我们现在介绍对GumTree的经验评估。Ourgoal将回答以下研究问题:RQ1)GumTree是否会产生正确且优于Unix diff(5.1)的树差异?RQ2)与现有算法(5.2)相比,GumTree是否最大化了映射数并最小化了编辑脚本大小?RQ3)GumTree是否比ChangeDistiller(5.3)更好地检测移动操作?我们在5.4中讨论了对结果有效性的威胁。

5.1 手动评估

首先,我们考虑开发者的观点。对她来说,重要的是计算的编辑脚本能够很好地理解提交的本质。从这个角度来看,我们开发了一个实验,它有两个主要目标:1.评估GumTree的正确性,2.比较GumTre与基于文本行的差异。

5.1.1 概述

实验包括手动评估文件差异,即手动评估文件对差异(提交前版本与提交后版本之间的差异)。使用两种技术计算这些文件差异;GumTree和最先进的文本差异工具5.我们将文本差异工具称为diff,将GumTre称为GT。对于数据集的每个文件对,两种方法的输出都会提供给人类评估者。他/她比较两个输出,然后回答以下问题:GumTree输出是否正确?哪种技术产生了最容易理解的差异信息:GumTree还是diff?。

5mergely.com

例如,DNSJava项目6的ARecord类1.15版在名为rrToWire的方法中引入了一个新参数(int索引)。diff输出是一个源代码块对:左边的块由与修订版1.14中的前一个方法签名对应的行组成。右边的块对应于修订版1.15中更新的方法签名。GumTree输出表示有一个新的参数类型和一个新参数名称。在这种情况下,评估人员可能会决定,与Unix diff相比,GumTree更准确地定位和描述了1.15版引入的更改。

6sf.net/projects/dnsjava

5.1.2 实验设置

提交由一组修改过的文件组成。提交后,每个修改的文件都会有一个新的修订。在我们的实验中,每个文件对对应于连续的文件修订。我们使用分层抽样从16个开源项目的软件历史中随机选择修订版本(来自[23])。我们只考虑源代码更改很少的修订(ChangeDistiller差分算法声明只有一个源代码更改的修订)。我们为每个项目挑选10个项目(文件对)(如果发现10个简单的修订版本更少)。数据集总共包含144个事务。

然后,我们为评估数据集的每对文件创建一个评估项。评估项包含:事务的修订对之间的GumTree输出、同一对之间的diff输出以及与事务关联的提交消息。

diff输出显示两个文件(即称为左和右),并突出显示每行所做的更改。特别是,它突出显示从左文件中删除的行,以及从右文件中添加的行。请注意,我们已经将diff配置为丢弃空格。GumTree输出(如图1所示)突出显示了添加、删除、更新和移动的AST节点。提交消息描述了更改的意图,有时有助于有意义地评估两种差异算法的相关性。

这144个评估项目由三位被称为评分者的作者独立评估。所有3名评分员在AST和行级别(即288个输出)评估了144个文件对的所有编辑脚本。这使得总共有3×2×144=864个评级。评分员必须回答以下问题:

  • 问题1:GumTree做得好吗?可能的答案是:
    1. GumTree做得很好:它有助于理解变化。
    2. GumTree做得不好。
    3. 中性。
  • 问题2:GumTree比diff好吗?可能的答案是:
    1. 树胶树更好。
    2. 比较好。
    3. GumTree相当于diff。

或者,评分者可以写评论来解释他的决定。这些评论用于识别GumTree可以改进的缺陷或角落案例。

5.1.3 实验结果

表1(顶部)列出了第一个问题的协议数量。让我们考虑问题1,三位评分者完全同意122/144(84.7%)个文件对,认为GumTree在解释这一变化方面做得很好。如果我们认为大多数人(至少有2/3人同意),我们认为GumTree对于137/144个文件对(95.1%)具有良好的输出。

在这里插入图片描述

表1:三名评分员对问题#1(顶部)和问题#2(底部)的144笔交易进行手动检查的协议。

表1(底部)列出了第二个问题的协议数量。在28/144(19.4%)个评估项目中,大家一致认为GumTree更好地突出了两个文件之间的变化。在45/144(31%)项中,评分者完全同意GumTree的输出与diff的输出一样好,可以解释这一变化。这直观地表明,与diff相比,GumTree是一个具有附加值的工具。除了这些原始数据,现在让我们来衡量一致性的统计水平。

5.1.4 统计

让我们假设pi测量单个项目的一致程度(在我们的例子中为{1 3,2 3,3 3})。总体一致性?P[9]是pi的平均值,其中i∈ {1, . . . , 144}. 系数κ(Kappa)[9,16]通过去除机会因子来衡量对协议水平的信心7

7当评级纯粹是随机的[9,16]时,预计会有一定程度的一致性。

  1. 对于问题#1:我们的P=0.905。使用[18]引入的量表,该值表示几乎完全一致。在我们的研究中,κ一致度为0.321,这是一个远离临界值的值,即0。无效假设被拒绝,观察到的一致性不是偶然的
  2. 对于问题#2:我们的P=0.674。使用上述比例,该值意味着费率之间存在实质性的总体一致性。我们研究中的κ一致度为0.426,远高于临界值。无效假设被拒绝,观察到的一致性不是偶然的。
5.1.5 结论

3名独立评分员对144次修订的手动评分表明:1)GumTree可以用来比较两个Java文件,以了解更改的本质;2)它的输出有时比diff的输出更容易理解。评分员对这两个结果的一致性在统计学上具有显著性。

5.2 自动评估

我们现在确信,从人类开发者的角度来看,GumTree是好的。我们现在评估GumTree是否最大化了映射的数量并最小化了编辑脚本。与之前的手动评估相比,此评估是完全自动的。因此,可以大规模进行。

5.2.1 目标和措施

本实验的目的是测量树差分算法在以下方面的性能:

  1. 映射的数量;
  2. 编辑脚本大小;

我们将GumTree与两种主要的差异算法(截至今天)进行比较:ChangeDistiller[13]和RTED[27]。其他算法也存在,但与这两种算法相比,它们的影响较小(在出版物可见性或引用方面)。有关ChangeDistiller和RTED的说明,请参阅第6节

如第6节所述,ChangeDistiller使用简化的AST,其中叶节点是代码语句。因此,我们计算简化AST(如[13]所述)和EclipseJDT解析器生成的原始AST的度量。在本节的剩余部分中,这些粒度分别称为CDG(ChangeDistiller粒度)和JDTG(EclipseJDT粒度)。我们的动机是比较GumTree和ChangeDistiller算法,即使是在CDG AST上:在AST上声称任何与ChangeDistriller设计和优化的算法不同的东西都是不公平的。由于GumTree的目标是在细粒度的AST上工作,因此我们也会在这个粒度上评估性能指标。最后,为了便于比较,我们还评估了细粒度AST的RTED,因为这是GumTree设计的粒度。

5.2.2 程序

实验包括使用几种AST差分算法比较源代码文件对。我们从CVS Vintage数据集的16个Java开源项目中抽取了1000个修订对的样本[23]。对于修订对,我们创建了4个树表示(在提交之前和之后,以及我们考虑的两种AST)。然后,我们为每对AST运行竞争树差分算法。最后,我们测量执行时间,计算映射的节点,并保存编辑脚本。为了提高性能,我们丢弃了大型源代码文件的修订对,即其树表示有3000多个节点(主要是因为ChangeDistiller算法对于大型AST来说太慢)。总共有12792个评估案例。

*复制信息:*对于GumTree,我们使用以下阈值:minHeight=2、minDice=0.5和maxSize=100。对于ChangeDistiller,我们使用标签相似性阈值0.5。对于不匹配的节点,我们使用两个相似性阈值:0.6用于包含4个子节点的内部节点,0.4用于其他节点。

5.2.3 实验结果

结果如表2所示。表的上部显示了ChangeDistillerGumTreeCDG粒度下的性能比较;而中间部分以JDTG粒度(更细的粒度,更多的AST节点)显示它们。最后,下半部分比较了在JDTG粒度下的GumTreeRTED差分算法。这些表中的每个单元格都显示了对于给定AST粒度和度量,一种方法优于另一种方法的情况数。我们现在用度量分析实验结果。

在这里插入图片描述

表2:在CDG粒度(顶部)和JDTG粒度(中部、底部)下,GumTreeChangeDistiller(顶部、中部)和RTED(底部)在2个指标映射数和编辑脚本大小(ES大小)方面更好(分别是较差和等效)的情况数。

映射。

如第2节所述,找到映射是AST差分算法中最重要的步骤。找到更多的映射会增加演绎简短编辑脚本的几率。考虑到CDG粒度,在4 007(31.32%)的情况下,GumTree比ChangeDistiller匹配更多的节点。然后,在8243例(64.44%)中,两种方法都找到了相同数量的映射。在JDTG粒度(更细的粒度)下,在8378(65.49%)例中,GumTree比ChangeDistiller匹配更多的节点。在4211例(32.92%)中,映射数相同。在这两种粒度下,GumTree比ChangeDistiller匹配更多的节点。

当比较GT和RTED时,在大多数情况下,8752(68.42%)发现了相同数量的映射。然而,GumTree发现了更多的映射,这比相反的2806(21.94%)和1234(9.65%)好两倍多。

编辑脚本大小。

找到映射后,将计算编辑脚本。编辑脚本的长度代表了开发人员理解提交本质的认知负荷。因此,目标是最小化编辑脚本的大小。

考虑到CDG粒度,GT和ChangeDistiller的编辑脚本大小在7442例(58.18%)中相同。在4938(38.6%)例中,ChangeDistiller的编辑脚本比GumTree的编辑脚本长(即GumTre通常更好)。对于JDTG粒度,同样,ChangeDistiller通常会生成更大的脚本:在10358(80.97%)个案例中(而在175个案例中,它的性能比GumTree好)。

GT和RTED之间的比较表明,在大多数情况下(59.25%),编辑脚本大小相同,在23.6%的情况下,GT生成的编辑脚本比RTED更短。

根据我们的数据集,GumTree系统地生成较短的编辑脚本,这有助于更好地理解提交的含义。

5.3 移动动作分析

GumTree和ChangeDistiller都能够检测移动节点动作。本节介绍对GumTree和ChangeDistiller匹配算法发现的移动动作的分析。本实验的目的是检查这些算法如何检测移动动作。

评估指标不能是检测到的移动操作的绝对数量。原因有两方面。一方面,人们希望最大化移动次数(而不是添加和删除)。另一方面,人们希望尽量减少与概念变化无关的虚假检测移动动作的数量。

因此,我们需要一个更微妙的评估场景。我们建议通过对两种算法的结果进行分层来比较移动次数。例如,如果ChangeDistiller能够完全解释仅使用移动操作的提交,那么GumTree还应该找到一个由移动组成的编辑脚本。在这种情况下,可以合理地认为移动次数最少的编辑脚本是最好的。因此,我们比较了许多不同子案例的结果。

5.3.1 程序

我们从第5.2节中介绍的数据集的Java文件对的差异中分析移动动作。我们重点关注ChangeDistiller(CD)和GumTree(GT)生成的编辑脚本中的移动动作。在这个实验中,我们不考虑RTED,因为这个算法不能识别移动动作。我们选择ChangeDistiller或GumTree中的编辑脚本仅由移动动作组成的Java文件对。从最初的12 792个文件对的数据集中,这产生了130个元素。

然后,为了比较编辑脚本,我们将每对编辑脚本(ChangeDistiller与GumTree)分为以下类别。

  1. ChangeDistiller和GumTree只产生移动。两者都有相同数量的动作,即它们相等(左上角)。

  2. ChangeDistiller和GumTree只产生移动,但数量不同(左上角)。

    (a) 有更多动作的GumTree。

    (b) 用更多的动作改变蒸馏器。

  3. ChangeDistiller只产生移动动作,而GumTree其他动作可以包括移动(右上角)。4.GumTree只生成移动动作,ChangeDistiller生成其他动作(左下角)。

对每一类别中的项目数量的分析使我们能够解决移动动作检测的有效性问题。

5.3.2 实验结果

结果如表3所示。有77个比较,其中两个匹配算法只产生移动动作,这77个案例中的58个对应于案例1,其中两种算法都产生相同的编辑脚本(相同的移动次数)。然后,有18个ChangeDistiller具有更多移动动作的实例(案例2-b)。这仍然是GumTree产生更多移动的一种情况(情况2-a)。这表明,与ChangeDistiller相比,GumTree编辑脚本更简洁地描述移动操作。

在这里插入图片描述

此外,有52种不同的场景,其中GumTree仅生成移动动作,而ChangeDistiller生成其他类型的动作(案例4)。在这些情况下,除了移动之外,ChangeDistiller还有其他操作(例如添加一个节点和删除一个节点)。这意味着GumTree更精确地表示涉及移动动作的更改。总之,根据我们的数据集,GumTree在检测移动动作方面优于ChangeDistiller;它既简洁又精确。

5.4 对有效性的威胁

我们现在讨论对我们的评估设置有效性的威胁。我们首先讨论研究问题的特定问题,然后讨论一般问题。

对于手工分析,对有效性的主要威胁是评分者也是本文的作者。为了让读者放心,评估数据集是公开的8

8www.labri.fr/~falleri/dist/articles/GumTree

对于不同工具之间映射和移动操作数量的比较分析,主要威胁是我们实现中的一个潜在缺陷。特别是,我们重新实现了ChangeDistiller,因为最初的实现需要一个Eclipse堆栈。我们的新实现可能不会反映原始实现的所有具体实现决策,甚至不会引入新的bug。为了将来的分析和复制,我们对竞争对手的实施与GumTree位于同一个存储库中。我们还注意到,我们已经在几个实验中(例如[20])对原始的ChangeDistiller进行了实验,并且确信我们的实现反映了原始的Change Distiller。

我们的实验只考虑Java文件的编辑脚本。这是对外部有效性的威胁。尽管不太可能(我们的算法独立于任何Java特性),但我们不能断定GumTree在其他编程语言上是否表现得如此出色。

最后,GumTree的三个阈值被固定为以下值: m i n H e i g h t = 2 minHeight=2 minHeight=2 m a x S i z e = 100 maxSize=100 maxSize=100 m i n D i c e = 0.5 minDice=0.5 minDice=0.5。这些值是根据我们的专业知识选择的。但是,其他值的性能可能不同。需要更多的实验来评估它们对运行时效率和算法结果的影响。

6 相关工作

在本节中,我们将介绍从文本到图形粒度的代码差异相关工作。

文本差异。

计算源文件的两个版本之间的差异通常在文本行粒度上执行[24,22]。在此粒度内,编辑操作是插入、删除或更新文本行。更先进的算法甚至能够检测移动的线条[29,5,3]。使用这种粒度的算法通常非常快速,完全独立于语言,而我们的方法需要一个解析器来减缓整个过程。这些算法的主要问题是它们无法计算细粒度差异。事实上,在许多语言(如JavaScript或Java)中,文本行可以包含许多编程结构。此外,这些算法的输出很难自动处理,因为它由可能无法解析的源代码行组成,因为它们可能不完整。因此,使用这些方法很难自动提取句法修改。

树和AST差异。

当只考虑添加节点、删除节点和更新节点操作时,树差异问题已被大量研究[4]。对于这个问题,文献中描述了许多优化算法。这一系列中最快的算法[27]运行在 O ( n 3 ) O(n^3) O(n3)中,这会导致大型源代码文件的编辑脚本计算时间显著延长。这些算法面临的另一个问题是它们无法发现移动的节点,这是源代码文件中的常见操作。这会导致不必要的大编辑脚本,难以理解。

当考虑移动节点操作时,在两棵树之间找到最短的编辑脚本的问题变成NPhard。然而,文献中存在一些来自文档工程或软件工程研究领域的算法,这些算法使用实际的启发式。其中最著名的是Chawathe等人[6]的算法,该算法在表示LaTeX文件的树上计算编辑脚本(包含移动动作)。不幸的是,该算法有一些约束(非循环标签和包含大量文本的叶节点),这些约束不适用于通用编程语言的细粒度AST。还专门为XML文档设计了几种算法[8,1]。与Chawathe等人的算法不同,它们没有任何特定的约束。然而,这些算法特别强调编辑脚本的计算时间,因为它们主要用于动态自动压缩。关于我们的目标,最重要的是计算一个能很好地反映开发人员意图的编辑脚本,计算时间只是次要的。GumTree的灵感来自Cobena等人[8]的算法,因为我们应用了非常相似的第一阶段。主要的区别在于,他们对细粒度的差异不感兴趣,因为差异仅为压缩目的而计算。我们的算法更准确,因为它还执行第二阶段,增加了找到的映射的数量,因此以牺牲运行时间为代价生成最短的编辑脚本。

在AST上最著名的算法是ChangeDistiller[13]。它在很大程度上受到了Chawathe等人的启发,但在AST上工作得更好。然而,该算法仍然基于叶节点包含大量文本的假设。因此,作者使用简化的AST,其中叶实际上是代码语句,而不是原始的AST。因此,ChangeDistiller不会在语句中包含大量元素的语言(如JavaScript)上计算细粒度的编辑脚本。Diff/TS算法[15]能够在原始AST上工作。

在原始文章中进行的自动实验表明,它可以有效地生成简短的编辑脚本。然而,该算法的结果尚未被人类验证。VDiff算法[10]从Verilog HDL文件生成编辑脚本。它与GumTree的第一阶段稍有相似,但它也使用了代码的词汇相似性。但是,生成的编辑脚本特定于VHDL语言。最后,JSync[25]算法还能够计算包含移动动作的编辑脚本。然而,它依赖于应用于未解析AST的经典文本差分算法作为第一步。因此,它限制了查找移动节点的能力。此外,它专注于生成有关克隆的信息,而不是编辑脚本。

图形差异和原点分析。

有几种算法超越了AST结构,在表示源代码的图上计算编辑脚本[28,31,2,11]。尽管这些算法可以揭示语义差异,但它们在实践中使用起来要困难得多。主要是因为它们需要更多关于源代码的语义信息(如程序依赖图、类模型、元模型或控制流图),这在许多语言(如JavaScript或C)中很难获得,或者仅考虑程序片段(如插件)。

最后,还有许多算法执行所谓的原点分析(例如,[14,30])。这些算法输出两个版本之间匹配的程序元素。它们通常使用元素之间的词汇和结构相似性。然而,它们只考虑几种程序元素(通常是类、函数和属性),不输出编辑脚本。

7 结论和未来工作

在本文中,我们提出了一种新的算法,用于计算AST上的细粒度编辑脚本,包括移动节点操作。我们的算法是在一个自由可用和可扩展的工具中实现的。我们已经评估了工具的运行时间和内存消耗,并表明它在实际数据上是合理的,可以每天使用。我们还对工具的结果进行了实证评估。该评估表明,我们算法的结果很好,通常比经典文本比较的结果更容易理解。

作为未来的工作,我们计划扩展我们的工具,以提取跨文件执行的修改。我们还计划引入新的算法,可以自动处理GumTree的编辑脚本,以生成更高阶的编辑脚本(例如,识别重构)。最后,由于这种方法的瓶颈是解析,我们考虑使用更多的模糊解析器,以接受格式不正确的文件并减少解析时间。

8 参考文献

[1] R. Al-Ekram, A. Adma, and O. Baysal. diffX: an algorithm to detect changes in multi version XML documents. In CASCON, page 1–11, 2005.

[2] T. Apiwattanapong, A. Orso, and M. J. Harrold. A differencing algorithm for object-oriented programs. In Proceedings of the 19th International Conference on Automated Software Engineering, ASE ’04, page 2–13, Washington, DC, USA, 2004. IEEE Computer Society.

[3] M. Asaduzzaman, C. K. Roy, K. A. Schneider, and M. D. Penta. LHDiff: a language-independent hybrid approach for tracking source code lines. In International Conference on Software Maintenance, Eindhoven, pages 230–239, 2013.

[4] P. Bille. A survey on tree edit distance and related problems. Theor. Comput. Sci., 337(1-3):217–239, 2005.

[5] G. Canfora, L. Cerulo, and M. Di Penta. Tracking your changes: A language-independent approach. Software, IEEE, 26(1):50–57, Jan. 2009.

[6] S. S. Chawathe, A. Rajaraman, H. Garcia-Molina, and J. Widom. Change detection in hierarchically structured information. In Proceedings of the 1996 International Conference on Management of Data, pages 493–504. ACM Press, 1996.

[7] M. Chilowicz, E. Duris, and G. Roussel. Syntax tree fingerprinting for source code similarity detection. In The 17th International Conference on Program Comprehension, pages 243–247. IEEE Computer Society, 2009.

[8] G. Cobena, S. Abiteboul, and A. Marian. Detecting changes in XML documents. In R. Agrawal and K. R. Dittrich, editors, Proceedings of the 18th International Conference on Data Engineering, pages 41–52. IEEE Computer Society, 2002.

[9] J. Cohen et al. A coefficient of agreement for nominal scales. Educational and psychological measurement, 20(1):37–46, 1960.

[10] A. Duley, C. Spandikow, and M. Kim. Vdiff: a program differencing algorithm for verilog hardware description language. Automated Software Engineering, 19(4):459–490, 2012.

[11] J.-R. Falleri, M. Huchard, M. Lafourcade, and C. Nebut. Metamodel matching for automatic model transformation generation. In Proceedings of the 11th International MoDELS Conference, pages 326–340. Springer, 2008.

[12] J.-R. Falleri, C. Teyton, M. Foucault, M. Palyart, F. Morandat, and X. Blanc. The harmony platform. CoRR, abs/1309.0456, 2013.

[13] B. Fluri, M. Würsch, M. Pinzger, and H. Gall. Change distilling: Tree differencing for fine-grained source code change extraction. IEEE Trans. Software Eng., 33(11):725–743, 2007.

[14] M. Godfrey and L. Zou. Using origin analysis to detect merging and splitting of source code entities. IEEE Transactions on Software Engineering, 31(2):166–181, 2005.

[15] M. Hashimoto and A. Mori. Diff/TS: a tool for fine-grained structural change analysis. In A. E. Hassan, A. Zaidman, and M. D. Penta, editors, Proceedings of the 15th Working Conference on Reverse Engineering, pages 279–288. IEEE, 2008.

[16] F. L. Joseph. Measuring nominal scale agreement among many raters. Psychological bulletin, 76(5):378–382, 1971.

[17] T. Kalibera, P. Maj, F. Morandat, and J. Vitek. A fast abstract syntax tree interpreter for R. In VEE, pages 89–102. ACM Press, 2014.

[18] J. R. Landis and G. G. Koch. The measurement of observer agreement for categorical data. Biometrics, 33(1):159–174, Mar. 1977.

[19] M. M. Lehman. On understanding laws, evolution, and conservation in the large-program life cycle. J. Syst. Softw., 1:213–221, Sept. 1984.

[20] M. Martinez and M. Monperrus. Mining Software Repair Models for Reasoning on the Search Space of Automated Program Fixing. Empirical Software Engineering, Online First, Sept. 2013. Accepted for publication on Sep. 11, 2013.

[21] T. Mens and S. Demeyer. Software Evolution. Springer, 1 edition, 2008.

[22] W. Miller, Eugene, and W. Myers. A file comparison program. Software: Practice and Experience, page 1040, 1985.

[23] M. Monperrus and M. Martinez. CVS-Vintage: A Dataset of 14 CVS Repositories of Java Software.

[24] E. W. Myers. An o(ND) difference algorithm and its variations. In Algorithmica, pages 251–266, 1986.

[25] H. A. Nguyen, T. T. Nguyen, N. H. Pham, J. M. Al-Kofahi, and T. N. Nguyen. Clone management for evolving software. IEEE Trans. Software Eng., 38(5):1008–1026, 2012.

[26] N. Palix, G. Thomas, S. Saha, C. Calv` es, J. Lawall, and G. Muller. Faults in linux: ten years later. In Sixteenth International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS 2011), page 305. ACM Press, 2011.

[27] M. Pawlik and N. Augsten. RTED: a robust algorithm for the tree edit distance. PVLDB, 5(4):334–345, 2011.

[28] S. Raghavan, R. Rohana, D. Leon, A. Podgurski, and V. Augustine. Dex: A semantic-graph differencing tool for studying changes in large code bases. In 20th International Conference on Software Maintenance, pages 188–197. IEEE Computer Society, 2004.

[29] S. Reiss. Tracking source locations. In Software Engineering, 2008. ICSE ’08. ACM/IEEE 30th International Conference on, pages 11–20, May 2008.

[30] W. Wu, Y.-G. Gu´ eh´ eneuc, G. Antoniol, and M. Kim. AURA: a hybrid approach to identify framework evolution. In Proceedings of the 32nd ACM/IEEE International Conference on Software Engineering - Volume 1, ICSE ’10, page 325–334, New York, NY, USA, 2010. ACM.

[31] Z. Xing and E. Stroulia. UMLDiff: an algorithm for object-oriented design differencing. In Proceedings of the 20th IEEE/ACM international Conference on Automated software engineering, ASE ’05, page 54–65, New York, NY, USA, 2005. ACM.

  • 30
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值