软件学报  2018, Vol. 29 Issue (8): 2226-2242   PDF    
融合结构与语义特征的代码注释决策支持方法
黄袁1,2, 贾楠1,6, 周强1,2, 陈湘萍2,3, 熊英飞4,5, 罗笑南1,2     
1. 中山大学 数据科学与计算机学院, 广东 广州 510006;
2. 国家数字家庭工程技术研究中心, 广东 广州 510006;
3. 中山大学 先进技术研究院, 广东 广州 510006;
4. 北京大学 信息科学技术学院 软件研究所, 北京 100871;
5. 高可信软件技术教育部重点实验室(北京大学), 北京 100871;
6. 河北地质大学 管理科学与工程学院, 河北 石家庄 050031
摘要: 代码注释是辅助编程人员理解源代码的有效手段之一.高质量的注释决策不仅能够覆盖软件系统中的核心代码片段,还能避免产生多余的代码注释.然而在实际开发中,编程人员往往缺乏统一的注释规范,大部分的注释决策都取决于个人经验以及领域知识.对于新手程序员来说,注释决策显然成为一项重要而艰巨的任务.为了减少编程人员投入过多的精力在注释决策上,从大量的代码注释实例中学习出一种通用的注释决策规范,并提出了CommentAdviser方法,以辅助编程人员在代码开发过程中做出恰当的注释决策.由于注释决策与代码本身的上下文信息密切相关,因此,从当前代码行的上下文代码中提取代码结构特征以及代码语义特征作为支持注释决策的主要依据.然后,利用机器学习算法判定当前代码行是否为可能的注释点.在GitHub中的10个大型开源软件的数据集上评估了所提出的方法,实验结果以及用户调研表明,代码注释决策支持CommentAdviser方法的可行性和有效性.
关键词: 代码注释     结构特征     语义特征     机器学习     注释决策    
Method Combining Structural and Semantic Features to Support Code Commenting Decision
HUANG Yuan1,2, JIA Nan1,6, ZHOU Qiang1,2, CHEN Xiang-Ping2,3, XIONG Ying-Fei4,5, LUO Xiao-Nan1,2     
1. School of Data and Computer Science, Sun Yat-sen University, Guangzhou 510006, China;
2. National Engineering Research Center of Digital Life, Guangzhou 510006, China;
3. Institute of Advanced Technology, Sun Yat-sen University, Guangzhou 510006, China;
4. Institute of Software, School of Electronics Engineering and Computer Science, Peking University, Beijing 100871, China;
5. Key Laboratory of High Confidence Software Technologies(Peking University), Ministry of Education, Beijing 100871, China;
6. School of Management Science and Engineering, Hebei GEO University, Shijiazhuang 050031, China
Foundation item: National Key Research and Development Program of China (2016YFB1000101); National Natural Science Foundation of China (61672545, 61402546); Science and Technology Planning Project of Guangdong Province (2013B090700009); Science and Technology Planning Project of Zhongshan City (2016A1044)
Abstract: Code comment is quite important to help developer review and comprehend source code. Strategic comment decision is desired to cover core code snippets of software system without incurring unintended trivial comments. However, in current practice, there is a lack of rigorous specifications for developers to make their comment decisions. Commenting has become an important yet tough decision which mostly depends on the personal experience of developers. To reduce the effort on making comment decisions, this paper investigates a unified commenting regulation from a large number of commenting instances. A method, CommentAdviser, is proposed to guide developers in placing comments in source code. Since making comment is closely related to the context information of source code themselves, the method identifies this important factor for determining where to comment and extract them as structural context feature and semantic context feature. Next, machine learning techniques are applied to identify the possible commenting locations in source code. CommentAdviser is evaluated on 10 data sets from GitHub. The experimental results, as well as a user study, demonstrate the feasibility and effectiveness of CommentAdviser.
Key words: code comment     structural feature     semantic feature     machine learning     comment decision    

在规范化的软件项目开发中, 为了保证源代码的易读性, 编程人员会被要求在源代码中适当的位置添加适量的代码注释[1].代码注释是软件项目的重要组成部分, 它用自然语言的形式阐述代码背后实现的逻辑或功能[2].因此, 代码注释是编程人员理解软件代码最直观和最有效的方式.高质量的代码注释在软件维护和软件复用等领域扮演着重要的作用[3].

总的来说, 代码中的注释可以分成3种类型[4], 即文档注释(javadoc)、块注释(block comment)以及行注释(line comment).其中, 文档注释用来描述一个类, 一个方法, 或类属性; 块注释用于描述1行或多行代码, 它们位于被注释代码(块)的上一行; 行注释是指跟在代码行后面, 并且与被注释代码处于同一行的注释, 它们只为当前代码行提供描述.文档注释可以由工具自动生成[5, 6], 而块注释和行注释则需要编程人员手动添加.因此, 在添加块注释和行注释时, 编程人员需要作出恰当的注释决策.

已有的注释决策方面的研究工作大多关注于代码注释量的统计与分析[7].软件代码中存在的注释量不能太少, 太少的代码注释难以覆盖系统中所有核心的代码片段, 这就会增加编程人员理解代码的难度, 从而增加他们审阅代码时的时间开销; 其次, 软件代码中的注释也不能过多, 因为过多的注释意味着更多的工作量, 这就要求编程人员花费更多的精力在代码注释上, 从而影响开发人员的编程效率.我们统计了10个在软件工程研究中经常用到的开源项目[8-11], 发现这些项目方法体内部的注释行数与代码行数的比例平均为1:9.5, 如图 1(a)所示.这项统计结果表明, 方法内部的注释数量和代码数量之间存在某种比例权衡.

Fig. 1 Statistical results 图 1 统计结果

然而, 即使保证了代码数量与注释数量的比例权衡, 如果将相同数量的注释添加到代码中的不同位置, 它们对于编程人员理解代码所起的辅助作用显然也是不同的.编程人员总是倾向于在核心或较难理解的代码片段上添加注释.为了验证编程人员对于注释位置的决策是否存在共识, 我们做了一项问卷调查.我们从数据集中抽取了20个方法体的代码片段, 然后要求8位参与者在每块代码片段中添加2处或3处块注释(其中, 15个代码片段要求添加2处块注释, 5个代码片段要求添加3处块注释, 共45个注释位置决策).8位参与人员都具有3年以上的Java编程经验.最终的统计结果如图 1(b)所示.在所有的45个注释位置决策中, 被6个或6个以上的参与人员达成共识(即至少6/8的调研人员达成共识)的注释位置决策占71.1%, 达到了32个.如果将每个注释位置决策上达成共识的参与人员数量限制在5个或5个以上(即至少5/8的调研人员达成共识), 则这个比例将达到88.9%, 即40个.因此, 调研结果证实了编程人员添加代码注释时存在统一的注释位置决策共识.

由此可见, 高质量的注释决策要求编程人员在实际开发中既要保持代码中均衡的注释数量, 又要保持统一的注释位置共识.然而, 查阅了相关的技术文档和研究报告[12, 13], 并没有统一的规范指导编程人员作出这样的注释决策.大部分情况下, 开发人员都需要借助自己的编程经验和领域知识做出判断.由此可见, 编程人员在开发过程中做出注释决策并不是一件容易的事情, 尤其是对于那些缺乏编程经验和领域知识的程序员新手.于是, 本文试图从已有的注释决策实例上学习一种通用的注释决策规范, 用于支持代码开发过程中的注释决策.具体而言, 我们提出了一种通过分析代码上下文信息辅助开发人员做出代码注释决策的方法——CommentAdviser.该方法从当前代码的上下文中获取了2种重要的信息, 分别是代码结构信息以及代码语义信息.其中, 代码结构信息表示了当前代码与上下文代码在位置、逻辑以及距离等方面的关系, 而代码语义信息则表示了当前代码的上下文代码的语义分布情况.使用这两种类型的信息就可以推测出当前代码与其上下文代码之间的逻辑耦合关系的强弱程度, 从而推测出当前代码行是否为可能的注释点.CommentAdviser基于学习的算法实现, 它从github上已有项目的注释实例中学习出一种通用的注释决策规范, 用以支持判定任意代码行是否为可能的注释点.开发人员借助于CommentAdviser推荐的注释点, 最终决定是否需要在相应位置处添加注释, 从而到达代码注释决策支持的目的.

我们在多个数据集上验证了文中提出的方法.实验结果表明:CommentAdviser推荐注释点的方法在正样本集上的精确度和召回率到达了80.8%和67.2%.本文的贡献有3点:首先, 提出了代码决策支持的可判别特征, 这使得注释决策支持成为可能; 其次, CommentAdviser可以为新手程序员提供了适当的注释建议; 最后, 提出了一套用于代码决策支持的评价机制.

文章第1节介绍基本概念.第2节介绍文章的主要方法、基于学习的注释决策支持方法将.第3节、第4节中将讨论实验设置与实验结果.第5节介绍用户调研情况.第6节介绍文章的相关工作.第7节对本文工作进行总结, 并对未来的工作进行介绍.

1 基本概念

文中为了区分源代码中的控制类型与非控制类型语句, 定义了控制类型代码行和非控制类型代码行, 然后给出了当前代码行的定义, 同时定义了上下文代码行的概念, 定义如下.

定义(控制类型代码行(control statement, 简称CS)).控制类型代码行负责程序的逻辑结构, 编程语言中常见的控制类型代码行包括CS={if, elseif, else, for, while, switch, try, catch, finally, do, synchronized}.

定义2(非控制类型代码行(non-control statement, 简称NCS)).非控制类型代码行是相对控制类型代码行定义的, 常见的非控制类型代码行包括赋值语句、变量申明语句、方法调用语句、返回语句等.NCS={Assignment, FieldDeclaration, MethodInvocation, ReturnStatement, BreakStatement, ...}, 满足CSNCS=∅.

定义3(当前代码行(current line, 简称CuL)).方法体内部的任意一行代码都可以作为当前代码行, 定义为五元组(al, cr, ia, ci, ST), 其中, al为当前代码行在方法体内部的绝对位置; cr为当前代码行的覆盖范围; ia为当前代码行所含标识符的数量; ci为当前代码行覆盖范围内标识符的数量; ST为当前代码行的类型, 取值为ST(CuL)∈{CSNCS}.如果ST(CuL)∈{NCS}, 则CuL.cr=0, 且CuL.ci=0.即非控制类型代码行的覆盖范围为0, 它覆盖范围内标识符的数量也等于0.

定义4(上下文代码行(context line, 简称CoL)).上下文代码行是相对于当前代码行定义的, 分为上文代码行(preceding line, 简称pl)和下文代码行(following line, 简称fl), 如图 2所示.任何一条上下文代码行CoL被定义为六元组(vi, mi, cd, dc, ic, cw), 其中, vi表示该CoL是否与CuL调用了同一个变量; mi表示该CoL是否与CuL调用了同一个方法; cd表示CoLCuL之间的距离; dc表示CoL是否与CuL位于同一条控制类型代码行覆盖范围内; ic表示CoL是否与CuL位于同一条控制类型代码行的覆盖范围内, 并且它们之间还存在其他的控制类型代码行; cwCoLCuL之间所有控制类型代码行的权重之和.

Fig. 2 Code snippet 图 2 代码片段示例

2 基于学习的注释决策支持方法 2.1 特征提取

本节详细介绍了从源代码中提取可判别特征的过程.由于编程人员所做的注释决策与代码行本身的上下文信息密切相关, 因此, 我们首先从两个维度共提取了11种类型的结构上下文特征, 这两个维度分别为代码自特征(intra-structural context feature)和代码间特征(inter-structural context feature); 同时, 为了获取当前代码行的上下文语义信息, 我们还使用词嵌入技术从代码中提取语义上下文特征.

2.1.1 结构上下文特征提取

代码具有良好的结构属性[14].

●  首先, 单行代码自身具有明显的结构特征, 称为代码自特征.5种常见的代码自特征见表 1:代码位置(Cloca)、代码类型(Ctype)、覆盖范围(Ccove)、标识符数量(Ciden)、覆盖范围内标识符数量(Cidencove).

Table 1 Structural context feature 表 1 结构上下文特征

●  另外, 代码与代码之间(文中特指CuLCoL之间)也具有明显的结构性特征, 称其为代码间特征(interstructural context feature).代码间特征表征了当前代码行与其上下文代码行在位置、距离、耦合关系等方面的信息.6种常见的代码间特征如表 1所示, 共同变量调用(Ccommvar)、共同方法调用(Ccommmet)、代码距离(Cdistance)、直接CS覆盖(Cdirecontr)、间接CS覆盖(Cindircontr)、CS权重(Ccontrweigh).

代码自特征Cloca表示了当前代码在方法体内部的绝对位置.如图 2所示, 深色背景高亮的代码为当前代码行, 它的绝对位置为5.特征Ctype表明了当前代码行的类型.从定义1和定义2可知, 代码行的类型可以分为控制类型和非控制类型.控制类型代码行又可细分为if, elseif, else, for, while等类型.而非控制类型代码行可细分为Assignment, FieldDeclaration等类型.特征Ccove表示当前代码行作为控制类型代码行时, 其覆盖范围内代码行的数量.如图 2中, 绝对位置为4的if控制语句的覆盖范围为2.Ccove的取值通过启发式规则确定.我们从数据集中观察到:62%的CS覆盖的代码行数在1行~9行之间; 28%的CS覆盖的代码行数在10行~29行之间; 只有10%左右的CS覆盖的代码行数大于30行.根据这个比例, 我们在不同的代码行区间内设置了Ccove不同的取值.特征Ciden表示当前代码行所包含的标识符数量.编程人员在给标识符命名时, 习惯遵循驼峰命名的规范.生成Ciden特征时, 以驼峰形式命名的标识符将被分解为单个单词再进行统计, 如structuralContextFeature分解为单词structural, context以及feature.特征Cidencove表示当前代码行覆盖范围内标识符数量.值得注意的是, 当前代码行本身的标识符数量并不计入Cidencove.因此, 如果当前代码行的类型为NCS时, 其特征Cidencove等于0.

代码间特征Ccommvar表示当前代码行与其上下文代码行是否调用了同一个变量.如图 2中所示, 当前代码行5与其上文代码行1调用了同一个变量hasBufferArgs.Ccommmet表示当前代码行与上下文代码行是否调用了同一个方法.图 2中, 当前代码行5与其下文代码行9调用了同一种方法setBuffer().为了判定两行代码是否调用了同一个变量或方法, 我们首先从源代码中识别出语法类型为variable-invocationmethod-invocation的代码行, 然后根据这些代码行中包含的标识符名称判定两行代码是否调用了同一个变量或方法.为了准确识别每行代码的语法类型, 我们使用基于抽象语法树(AST)的程序语法分析算法.特征Cdistance表示当前代码行与任意上下文代码行之间的距离, 如图 2中, 当前代码行5与其上文代码行1之间的Cdistance等于5.需要注意的是, 计算Cdistance时, 空行不能被算作1行, 但是大括号“{”和“}”可以被算作独立的代码行, 因为它们常常表示控制类型语句的开始或结束, 如图 2中的第7行、第11行、第12行.

特征CdirecontrCindircontr都是表示当前代码行和上下文代码行是否位于同一条控制类型代码行的覆盖范围内.不同的是:Cdirecontr表示CuLCoL位于同一条控制类型代码行的覆盖范围内, 且它们之间不存在其他控制类型代码行; 而Cindircontr则表示CuLCoL之间还存在其他控制类型代码行.如图 2所示, 当前代码行5和代码行6位于if控制语句(第4行)的覆盖范围内, 它们满足Cdirecontr特征.当前代码行5和代码行8位于for控制语句(第3行)的覆盖范围内, 但是它们之间还存在另外一条控制语句, 即第4行的if语句.因此, 当前代码行5和代码行8满足Cindircontr特征.为了判定CdirecontrCindircontr特征, 首先需要识别出代码片段中所有的控制类型代码行.我们再次使用基于抽象语法树的程序语法分析算法.该算法可以定位出每条控制类型代码行的开始位置和结束位置, 从而识别出它的覆盖范围.最终就可以判定当前代码行和上下文代码行是否位于同一条控制类型代码行的覆盖范围内.为了表征当前代码行和上下文代码行之间控制类型代码行的嵌套程度, 提出了特征Ccontrweigh.它通过计算当前代码行与任意上下文代码行之间存在的控制类型语句的权重之和获得.对于每种类型的控制类型代码行, 随机生成一个位于0, 1之间的10位浮点数作为其权重(比如, if语句的权重为0.1239239729, for语句的权重为0.2469030123).则图 2中当前代码行5和上文代码行1之间的Ccontrweigh特征值等于2×0.1239239729+0.2469030123(即两个if语句加上一个for语句).

关于结构上下文特征的详细介绍见表 1, 表中给出了每种类型特征的形式化描述及其取值范围.为了获取当前代码行CuL完整的结构上下文特征, 需要分析CuL与其前后η条上下文代码之间的代码间特征.比如η等于5时, CuL与其上文5条代码中的每一条代码之间有6种代码间特征, 共产生30维特征.同样, CuL与其下文5条代码中的每一条代码之间也有6种代码间特征, 再产生30维特征; 再加上CuL本身具有的5维代码自特征, 所以对于任意一条当前代码行CuL, 其完整的结构上下文特征共有65维.此外, 为了获得当前代码行的任意上文(或下文)代码行与其他上文(或下文)代码行之间的结构特征, 我们生成了任意上文(或下文)代码行与其他上文(或下文)代码行之间的结构上下文特征.为了使问题简化, 我们只生成上文(或下文)代码行与其他上文(或下文)代码行之间的结构特征.我们将在实验章节给出使得CommentAdviser表现最优的η值.

2.1.2 语义上下文特征提取

程序代码在某种程度上与自然语言类似, 因为代码中的标识符和自然语言中的单词一样, 具有丰富的语义信息[15].我们假设一个程序中的某段代码片段被添加了注释, 则位于其他程序中的具有相似语义的另外一段代码片段也很有可能被添加注释.如果这个假设成立, 就可以利用代码片段之间的语义相似度, 使用基于学习的方法去预测一段代码需要添加注释的可能性.但是两段具有相似语义的代码片段可能在标识符命名上选用不同的单词, 这就会极大地削弱常规语义相似度计算方法的效力, 很难获取到两块代码片段的真实相似度.为了克服这个困难, 我们引入了词嵌入(word embeddings)技术[16]对代码中出现的单词进行编码处理.

使用词嵌入方法编码单词时, 单词不再被视为独立的符号, 而是映射到一个稠密的、具有实值的高维向量空间中[16], 而其中每个维度表示该单词的潜在语义或句法特征.因此, 语义相似的单词在低维向量空间中具有更小的夹角.更重要的是, 词嵌入方法将位于相似上下文语境中的单词看作是语义相似的[16].因此, 即使是用词不同的两个标识符, 只要它们位于相似的上下文代码中, 词嵌入方法也认为它们是语义相似的, 这样就可以很好地表示两块代码片段真实的相似度, 避免使用常规语义相似度计算方法遇到的问题.

词嵌入方法是基于无监督学习的, 它可以从大量无标签的文本数据中学习单词的向量表示.文中, 方法体中的源代码被当做文本处理:首先, 从源代码中删除标点符号及运算符号, 并分割以驼峰形式命名的标识符; 然后过滤掉无意义的单词(如aaa, xxx等)以及虚词(如a, an, is等); 同时, 为了减少了整个语料库的词汇量, 将过去时、未来时态、完成时态等形式出现的动词统一转化为一般现在时; 最后, 过滤掉在整个语料库中出现次数少于3次的单词.经过以上处理后, 就可以获得源代码的文本形式.

为了获得源代码中每个单词的向量表示, 我们使用skip-gram模型学习每个单词的向量表达[16].我们所需要的单词向量表达其实是skip-gram模型在训练过程中的中间产物, skip-gram模型在已知当前单词的情况下, 擅长在2k+1的上下文窗口中预测周围单词(通常, k=2, 窗口大小为5).skip-gram模型的目标函数是最大化以下对数概率之和:

$ \sum\limits_{i = 1}^n {\sum\limits_{ - k \le j \le k, j \ne 0} {\log p({w_{i + j}}|{w_i})} } $

其中, wiwi+j分别表示在2k+1的窗口中, 位于中心的单词以及其上下文单词; n表示单词序列的长度.p(wi+j|wi)是用softmax函数定义的条件概率:

${\rm{log}}\ \mathit{p}\left( {{w}_{i+j}}\left| {{w}_{i}} \right. \right)=\frac{{\rm{exp}}\left( \mathit{{v}'}_{{{w}_{i+j}}}^{T}{{v}_{{{w}_{i}}}} \right)}{\sum\nolimits_{w\in W}{{\rm{exp}}\left( \mathit{{v}'}_{w}^{T}{{v}_{{{w}_{i}}}} \right)}}, $

其中, vwvw′分别表示单词w在skip-gram模型中的输入向量和输出向量, W为整个语料库.可以看出, p(wi+j|wi)是计算给定单词wi时, 单词wi+j出现在wi的上下文中的概率.文中, 我们使用负采样(negative sampling)优化该概率值的计算[16].

skip-gram模型训练完成后, 语料库中的每个单词都与一个向量相关联, 形成单词-向量词典.为了获得当前代码行的上下文代码的语义信息, 对于上下文代码行中的每个单词, 从字典中找出与之对应的向量表示.然后, 将每个单词的向量按维度叠加在一起.因为每个单词的向量具有上百维度(如300维), 因此, 最终上下文语义特征由百维向量表示.

2.2 特征选择与模型训练

从代码中提取结构上下文特征和语义上下文特征之后, 将这两种特征向量首尾相连, 就生成当前代码行的特征向量.值得注意的是:当方法体中的第1行代码作为当前代码时, 它没有上文代码行; 类似地, 方法体中的最后一行代码作为当前代码时, 它没有下文代码行.此时, 为了保持向量维度不变, 上文代码行(或下文代码行)的特征向量都用相同维度的零向量填充.

由于有两种类型的上下文特征, 并且每种类型的特征都可以被分为更细粒度的特征, 这将最终导致高维特征向量出现.然而, 特征向量中的某些维度有可能是无关紧要的, 甚至它们对预测模型的建立起负面作用.因此, 有必要去除不相关的特征维度, 从而降低整个特征向量的维数.文中, 我们采用信息增益去除掉不相关的特征维度.信息增益最初用于决定决策树中属性的排序, 它被广泛地用于评估特征向量中每个维度的重要性[17].对于处理后的特征向量, 我们可以使用一系列的机器学习算法(例如随机森林、决策树、朴素贝叶斯、支持向量机等)来训练并获取注释决策支持模型.在实验分析部分, 我们将进一步评估每种机器学习算法的准确率.

2.3 数据收集

我们在10个开源项目上进行了数据收集, 见表 2.它们分别是Ant, ANTLR, ArgoUML, ConQAT, JDT, JHotDraw, JabRef, JFreeChart, Lucene, Vuze.所有这些项目都是用Java语言编码, 并且具有10万行以上的代码规模.我们基于以下因素选择这10个项目作为数据集:首先, 这些项目都是开源的, 它们在软件工程相关的研究中具有较高的使用频率, 因此它们拥有广大的用户基础和贡献者; 其次, 这10个项目的版本更新较为活跃(大于2000个的代码提交)和悠久的演化历史(大于10年的演化历史), 我们从中选择相对稳定的版本作为数据集; 最后, 大部分这些项目隶属于正规组织(如Apache)或软件公司(如IBM), 因此, 这10个项目的具有较高的代码质量.

Table 2 Data set 表 2 数据集

我们相信, 这10个项目的源代码中具有较规范的注释实例.因为这些项目为了满足开源的需求, 必然需要提供高质量的代码注释供项目使用者或审核者进行代码分析、代码理解及代码审查.尤其是在经历了10多年的版本演化之后, 项目中的注释实例达到了一个较高的水准.此外, 这10个项目都由正规组织或软件公司中有经验的编程人员开发和实施的, 组织和公司内部必然会严格控制代码质量(包括注释质量).因此, 这10个项目中的注释实例非常适合用于注释决策的研究.

我们从这10个目标项目的源代码中收集包括正、负样本的数据集, 其中, 有注释的代码行对应正样本, 而没有注释的代码行对应负样本.具体来说, 对于方法中的每条代码行, 如果在它上一行有块注释(需要说明的是, 由于行注释随意性较强, CommentAdviser不考虑行注释的决策), 则该条代码行被标记为正样本, 它对应的标签为‘1’; 否则, 被标记为负样本, 其对应的标签为‘0’.但是, 并不是所有的正样本都纳入数据集, 因为某些正样本可能是噪声数据.例如, 我们观察到有些注释是以“//TODO”的形式存在.很显然, 这样的注释是由工具(例如Eclipse)自动生成的标记, 又或者是编程人员人为添加的标记, 用于提醒自己还未实现的功能.因此, “//TODO”被看作注释时没有实际意义.第2种噪声数据是被注释掉的代码行, 例如“//if (obj.getName()==null)”.这种情况在源代码中很常见, 它们可能是测试代码, 或者是开发人员改变原来的实现方案而废弃的代码.要过滤掉这样的注释, 我们定义了一系列特定的正则表达式来检测它们.另外, 还有一些特定的注释也需要被过滤, 例如不包含英文单词的注释(如“//:+ =”)、工具自动生成的注释(如//Auto-generated catch block)等.

3 实验验证 3.1 研究问题

本节将从多个角度评估CommentAdviser的表现.文章的主要目标是使用CommentAdviser判定当前代码行是否需要添加注释, 并将结果推荐给编程人员, 辅助编程人员做出注释决策.因此, 我们主要关注以下几方面的问题.

●  问题1:CommentAdviser判定注释点的精确度和召回率分别是多少?

●  问题2:不同的η值对CommentAdviser的准确率是否有影响?

●  问题3:两种类型的特征对CommentAdviser的准确率有何影响?

●  问题4:不同机器学习算法对CommentAdviser的准确率有何影响?

●  问题5:跨项目评估是否对CommentAdviser的准确率有影响?

3.2 评估方法

实验中, 我们调用Weka编程接口[18]进行机器学习模型训练与结果评估.Weka工具包实现了大部分常见的机器学习算法, 包括朴素贝叶斯、LogitBoost、随机树、决策树、支持向量机、随机森林等等.针对训练集中正负实例比例失衡的问题(正负比例大约为1:9.5), 使用Weka工具包自带的SMOTE算法[19], 人为地生成部分正样本, 使得训练集中的正负样本比例均衡, 而测试集中的正负样本保持原始比例不变.

在评估CommentAdviser的效果时, 我们在正样本集(positive instances)和负样本集(negative instances)上考察了3个指标:精确度(precision, 简称PRE), 召回率(recall, 简称REC)以及F值(F-measure, 简称FM).其定义如下:

$ PRE = \frac{{TP}}{{TP + FP}}, REC = \frac{{TP}}{{TP + FN}}, FM = 2 \times \frac{{PRE \times REC}}{{PRE + REC}}, \ $

其中, TP表示被正确分类的正样本, TN表示被正确分类的负样本, FP表示被错误分类的正样本, FN表示被错误分类的负样本.

精确度用来衡量结果集的精确性, 表示被CommentAdviser判定为需要添加注释的代码行集合与数据集中真正添加了注释的代码行集合的吻合程度; 而召回率用来度量结果集的安全性, 表示被CommentAdviser判定为需要添加注释的代码行集合能够覆盖真正添加了注释的代码行集合的程度.FM是调和平均数, 它是一个用来评估精确度和召回率的综合指标.精确度、召回率以及FM的定义同样适用于负样本集的评估.

4 实验结果 4.1 问题1:CommentAdviser判定注释点的精确度和召回率分别是多少?

表 3展示了10个数据集中正、负样本的数量.可以看出, 所有数据集中的正、负样本数量均不平衡.数据集JHotDraw的样本总量最少, 而数据集ArgoUML的样本总量最多.

Table 3 Number of positive and negative instances in the data sets 表 3 数据集中正负样本数量

表 4展示了CommentAdviser在10个数据集上的判定结果, 包括在正样本和负样本上的精确度、召回率、FM值.整个评估过程中, 使用随机森林算法以及10折交叉验证法.根据10折交叉验证的定义, 我们将每个数据集等分为10份, 其中1份作为测试集, 剩下9份作为训练集, 依次循环10次, 最后取10次判定结果的平均值.为了使训练集中的正负样本数量平衡, 使用SMOTE算法人为的生成部分正样本, 而测试集中的正负样本比例则保持不变.

Table 4 Evaluation results 表 4 判定结果

表 4中可以观察到, 负样本的平均精确度、召回率以及FM值都超过了0.96.这个结果表明, 数据集中大部分的负样本是可以被正确判定的.另一方面, 在正样本集上, CommentAdviser获得的平均精确度、召回率以及FM值只有0.735, 0.66以及0.665, 其与负样本上的准确率有较大的差异.66%的召回率说明, 大约有1/3的正样本没被正确判定.而较低的精确度(73.5%), 则有可能是因为测试集中正负样本比例相差悬殊造成的.由于这是一个二分类问题, 而负样本的数量又是正样本的10倍, 根据精确度的定义, 被错误分类的负样本将会加倍降低正样本的精确度.

总的来说, 在正样本集上较低的精确度和召回率, 说明CommentAdviser并没有充分地从源代码中学习到通用的注释决策.我们有理由相信:训练集中存在一小部分实例, 它们代表了错误的注释决策.比如:有的实例本应该添加注释的, 但其实并没有添加(此时实例的标签为0);而另外一些实例本不应该添加注释的, 却被添加了注释(此时实例的标签为1).这些实例都会影响机器学习算法建立有效的判定模型, 称为噪音数据, 因此有必要将噪音数据从数据集中过滤掉.

为了过滤数据集中的噪音数据, 使用了一种简单有效的噪音过滤方法CLNI[20].对于任意一个被检测的实例, CLNI判定其周围最近邻的k个实例的标签, 如果在这k个实例中有ϕ%的实例都与被检测的实例标签相反, 则被检测的实例标记为噪音数据.通常, k取值为5, ϕ取值为60[20].图 3中, 噪音比表示了每个数据集中的噪音实例所占的比例.可以看出, 在这10个数据集上, 噪音比从0.009 1上升到0.022 5.这个结果说明, 绝大部分实例与其周围的实例具有相同的标签.

Fig. 3 Noise degree in data sets 图 3 数据集中的噪音比

表 5所示, 经过去噪处理后, CommentAdviser在10个数据集的负样本上获得的平均精确度、召回率以及FM值都达到或超过了0.97.而在正样本上的平均召回率从0.66上升到了0.672, 平均精确度从0.735上升到了0.808;同时, 正样本上的平均FM值也达到了0.733.与去噪处理前相比, CommentAdviser在正样本和负样本上的所有指标均有所提升.这个结果足以说明, 适当地去除数据集中的噪音实例, 可以让CommentAdviser更有效地从源码中学习到通用的注释策略.

Table 5 Noise-Handling evaluation results 表 5 去除噪音数据后的判定结果

4.2 问题2:不同的η值对CommentAdviser的准确率是否有影响?

文章假设代码注释决策与代码本身的上下文代码行密切相关, 因此需要确定一个最优的上下文代码行η值, 使得CommentAdviser能够达到最佳的准确率.我们先后比较了η值为4, 5, 6, 7, 8时, CommentAdviser获得的精确度、召回率以及FM值.详细结果如图 4所示.

Fig. 4 Effectiveness of η values on the accuracy of CommentAdviser 图 4 η值对CommentAdviser准确率的影响

由于我们关心的是CommentAdviser在代码中做出注释决策的准确率, 也就是对应数据集中正样本的准确率, 因此, 图 4所示的结果为CommentAdviser在10个数据集的正样本集上的平均精确度、平均召回率以及平均FM值.整个判定过程中, 使用随机森林算法作为分类器, 并在每个数据集上使用10折交叉验证法.我们观察到:当η值等于6时, CommentAdviser获得最佳的精确度; 当η值等于5时, CommentAdviser获得最佳的召回率和FM值.仔细比较可以发现:当η值等于5时, CommentAdviser获得的精确度只比η值等于6时少0.004, 而此时的召回率却比η值等于6时高出0.015, FM值高出0.007.因此, 在文章的整个实验中, η值被设置为5, 即把当前代码行的前后5行代码作为其上下文代码行.

4.3 问题3:两种类型的特征对CommentAdviser的准确率有何影响?

文中, 我们假设代码注释决策与上下文代码的结构(structural)和语义(semantic)存在密切的关系, 因此提出了两种类型的特征用来判定代码中可能的注释点, 即上下文结构特征和上下文语义特征.为了验证文中提出的假设, 我们让CommentAdviser单独使用上下文结构特征和上下文语义特征进行注释决策判定, 然后再融合两种特征进行注释决策判定.该验证同样使用随机森林算和10折交叉验证法.表 6展示了CommentAdviser使用不同特征在10个数据集的正样本集上的评估结果.

Table 6 Features effect on evaluation results 表 6 不同特征下的判定结果

表 6所示, 当单独使用结构上下文特征时, CommentAdviser在10个数据集上的平均精确度、召回率以及FM值分别为0.771, 0.502和0.601;而单独使用语义上下文特征时, CommentAdviser在10个数据集上的平均精确度、召回率以及FM值分别为0.4, 0.825和0.535.可以看出, 结构上下特征让CommentAdviser获得较高的精确度, 而语义上下文特征能让CommentAdviser的召回率明显提高.当结合结构上下文特征和语义上下文特征时, CommentAdviser能获得较均衡的精确度和召回率, 此时的平均精确度、召回率以及FM值分别为0.808, 0.672, 以及0.733.这个结果表明:无论是在结构上下文特征中加入语义上下文特征, 还是在语义上下文特征中加入结构上下文特征, 都能对CommentAdviser准确率的提高起积极作用, 从而验证了文章中提出的假设.

4.4 问题4:不同机器学习算法对CommentAdviser的准确率有何影响?

在实验过程中, 我们还对比了多种机器学习算法在支持注释决策时的表现.参与比较的机器学习算法全是基于监督的学习算法, 它们是朴素贝叶斯、LogitBoost、随机树、C4.5决策树、支持向量机、随机森林.为了公平比较, 所有算法在实验之前都将它们各自的参数调到最优的水平.比如:设置随机森林算法的BagSizePercent= 30, 对于随机森林的每个分类器, 随机抽取原训练样本集的30%进行训练; 设置NumFeatures=20, 对于随机森林的每个分类器, 随机抽取特征集的20个特征进行训练; 设置NumIterations=300, 随机森林中包含300个分类器.

表 7例举了各种机器学习算法在10个数据集上的平均正样本F-measure和负样本F-measure.从结果中可以观察到:除了支持向量机和随机森林, 其他各种机器学习算法在支持注释决策上都表现欠佳.其中, 随机森林和支持向量机在正样本上的F-measure分别达到了0.733和0.71, 而其余4种算法的F-measure从0.24~0.469不等.总的来说, 随机森林算法的表现最优.因此, 在本文全部实验中, 随机森林算法被用作默认分类器.

Table 7 FM comparison of machine learning algorithms 表 7 机器学习算法FM比较

4.5 问题5:跨项目评估是否对CommentAdviser的准确率有影响?

以上4个问题都是在项目内(within-projet)进行的评估, 即训练集和测试集来自于同一个项目的数据集.在项目内评估时, CommentAdviser能够获得较高的精确度和召回率.这就使得CommentAdviser能够很好地应用于如下场景, 例如:在一个项目中需要开发新的组件时, CommentAdviser可以从该项目已有的注释实例中学习注释决策规范, 然后应用于新开发的组件中.然而在实际开发中, 很多项目都是从零开始, 此时并没有可以参考的原项目, 此时需要CommentAdviser通过跨项目(cross-project)学习, 然后在新项目中作出注释决策.

在跨项目评估中, 我们依然使用相同的10个数据集, 不同的是, 我们每次从其中一个数据集中随机抽取2 000条实例作为训练集, 而从剩下的9个项目中的每个项目随机抽取2 000条实例作为训练集.一共进行10次这样的评估.与项目内的注释决策相比, 跨项目注释决策的学习对于CommentAdviser来说更具挑战性.因为不同的项目在注释策略上可能存在较大的差异, 这就使得CommentAdviser很难学习到一种能够适合所有数据集的注释策略.为了尽量提升CommentAdviser的准确率, 我们选择那些在项目间被频繁共同使用的特征用作判别模型的训练, 比如代码自特征ClocaCtype, 以及代码间特征CcommvarCcommmet等等.

图 5展示了跨项目评估与项目内评估的结果对比.跨项目评估时, CommentAdviser在正样本上的精确度从0.808降到了0.655, 而召回率从0.672降到了0.528.这说明CommentAdviser在进行跨项目学习时, 它的效力出现了较严重的退化, 同时也印证了不同项目的注释策略存在较大的差异.

Fig. 5 Cross-Projects evaluation results 图 5 跨项目评估结果

而对于负样本的评估, CommentAdviser在精确度、召回率以及FM值上也呈现出不同程度的下降.我们将在用户调研章节进一步分析造成CommentAdviser低精确度和召回率的原因.

5 用户调研

CommentAdviser在正样本数据集上表现出较低的召回率, 这说明存在很多漏判的情况(即原本添加了注释的代码行被判定为不用添加注释, 对应FP), 而较低的精确度则说明存在很多误判的情况(即没添加注释的代码行被判定为应该添加注释, 对应FN).我们生成了所有数据集上被CommentAdviser漏判或误判的实例.通过分析这些被漏判或误判的实例, 发现了大量重复出现的案例.如图 6(a)所示, 图中的标记“//*********”表示被CommentAdviser误判的注释; 标记“//#########”表示被CommentAdviser漏判的注释.这种案例具有的一个共同特点, 即被CommentAdviser误判代码注释附近总是存在漏判的代码注释, 它们之间的距离一般不超过3行, 如图 6(a)所示, 我们称其为“误判漏判注释对”.通过观察大量的“误判漏判注释对”, 发现它们的作用范围存在交叉或覆盖的情况.如图 6(a)所示, 误判的注释①的作用范围覆盖了整个if语句, 而漏判的注释②的作用范围覆盖了整个if语句的内部代码.因此, 我们提出了一个假设, 即“误判漏判注释对”对于编程人员理解代码具有等价作用.也就是说, 误判和漏判的注释虽然在代码中处于不同的位置, 但是它们辅助编程人员理解代码时能够发挥同等的作用.

Fig. 6 FP & FN commenting pair and questionnaire 图 6 误判漏判注释对及问卷题目

为了验证这个假设, 我们以问卷的方式向20名参与者发起了用户调研.在这20位参与者中, 有1位高校教师, 4位博士研究生以及15位硕士研究生.所有参与者都来自中山大学, 并从事与计算机专业相关的工作或研究, 平均拥有2.5年以上Java编程经验.我们从所有误判和漏判案例中随机抽取了15个“误判漏判注释对”, 对应问卷调查中的15道题目, 每道题目共设置两个问题.参与者首先回答他/她认为代码片段中应该添加注释的位置, 他/她们事先并不知道标记“//*********”和“//#########”的区别; 然后再回答理解该段代码的难度, 难度等级分为极易、较易、适中、较难、极难.题目如图 6(b)所示.

我们按照参与者反馈的问题难易程度对问卷结果进行了统计, 如图 7所示.面对极易的题目时, 有9次参与者选择保留误判注释, 8次选择保留漏判注释, 如图 7(a)所示; 面对较易的题目时, 有35次参与者选择了保留误判, 37次选择了保留漏判.由此可知:对于极易和较易的代码片段来说, 参与者选择保留误判或漏判注释的概率几乎一样(即0.49:0.51, 如图 7(b)所示); 当面对难度适中的题目时, 有53次参与者选择了保留误判, 49次选择保留漏判, 13次选择二者均保留.这个结果同样表明:参与者在面对难度适中的代码片段时, 对于选择保留误判还是选择漏判没有显著性的差异; 当面对难度较难的题目时, 有26次参与者选择了保留误判, 29次选择保留漏判, 29次选择二者均保留.可以看出, 此时参与者更多的是希望二者均保留, 而对于选择保留误判还是选择漏判还是没有显著性的差异.当面对极难的题目时, 参与者在84%以上的情形下都会选择二者均保留, 如图 7(b)所示.通过对比所有难度下保留误判、保留漏判以及二者均保留的次数, 可以发现它们的比例分别为37.4%, 36.8%和25.8%.这个比例再次证明, 参与者在选择保留误判和选择漏判上没有显著性的差异.

Fig. 7 Questionnaire result 图 7 问卷调查结果统计

因此可以接受我们提出的假设, 即“误判漏判注释对”中的误判注释和漏判注释对于编程人员理解代码具有等价作用.事实上, 想要预测添加的注释在代码中的精确位置是件非常困难的事情.因为当前代码行的上下文代码有成千上万种可能, 在其上下文代码中增加或减少1行代码, 就可能影响当前代码的注释决策.这个结论也可以从CommentAdviser在正样本数据集上出现比较严重的漏判和误判中得出.但是从用户调研结果中可以看出, 很多误判的注释其实是与漏判注释存在作用范围交叉或覆盖的情况.也就是说, CommentAdviser作出的注释决策虽然没能恰好落在漏判的注释上, 但是却落在它的附近(不超过3行代码), 而这个距离能够帮助编程人员借助推荐的注释点理解代码.因此, 如果将“误判漏判注释对”也算作有效的注释决策, CommentAdviser的真实准确率会相应提高.

6 相关工作

注释决策的主要作用是告知编程人员应该在代码中何处添加注释, 从而有效地提高编程人员的开发效率.本文首先分析代码行的上下文结构信息和语义信息, 然后使用机器学习的算法定位出可能添加注释的代码行, 最后将注释决策推荐给开发人员.本节主要从3个方面介绍与本文相关的研究工作:首先介绍基于抽象语法树的程序结构分析; 然后介绍词嵌入技术在软件工程相关研究中的应用; 最后介绍与代码注释相关的研究和实践.

6.1 基于抽象语法树的程序结构分析

CommentAdviser首先分析代码自身和代码之间的结构信息, 从而获得代码的结构特征.文中提出的大部分结构特征是通过分析代码的抽象语法树获得的.近年来, 许多研究人员通过解析代码的抽象语法树而获得代码的语法结构, 然后将代码的语法结构用于各种各样与软件工程相关的研究中.

Mou等人[14]设计了一个基于抽象语法树的卷积神经网络, 他们提出的网络在抽象语法树上做卷积运算, 此操作更能够凸显出抽象语法树上的代码结构特征.最终, 他们的方法被用于程序功能自动识别中.此外, 抽象语法树被广泛地应用于基于树结构的代码克隆检测中.Dyer等人[21]从900万个Java文件中挖掘出超过10亿个抽象语法树节点, 他们试图从这些海量的抽象语法树节点中分析出Java版本发布的新特性在不同时间段内的使用情况.最终, 他们分析出了最受欢迎的Java新特性及其随着时间变化的使用情况.White等人[22]提出了一种基于语法与语义的代码克隆检测方法.与传统的基于树结构的代码克隆检测方法不同, 他们在提取代码结构信息时将抽象语法树转换为满二叉树.与此同时, 也有一些学者将抽象语法树应用于代码缺陷预测中, Wang等人[23]利用深度学习算法自动获得代码漏洞与代码语义信息之间的映射关系.在他们提出的方法中, 代码的语义信息从程序对应的抽象语法树上获得.为了修复代码中反复出现的崩溃错误, Gao等人[24]从编程问答网站上挖掘出可用于修复崩溃错误的fixed代码片段.他们通过比较buggy代码片段与fixed代码片段的抽象语法树, 从而获得从buggy代码片段转化到fixed代码片段的自动修复脚本.除此之外, 抽象语法树也成功地应用于编程模式识别[25]、代码修改模式识别[26]、软件演化[27]等领域.

6.2 词嵌入技术在软件工程相关研究中的应用

为了解决one-hot技术中可能出现的维度灾难问题, 研究人员引入了词嵌入技术[16].word2vec简化了词嵌入技术原有的模型, 使得训练速度大为提升, 使其成为最常见也是最实用的一种词嵌入技术.因此, word2vec也被众多学者应用于软件工程相关的研究中.

Xu等人[28]认为, 开发者问答社区(stack overflow)上, 围绕每个问题都能构成一个知识单元; 而在解答问题的过程中, 开发者往往会引用其他相关联的知识单元来解决当前问题.为度量知识单元之间的语义相关性, 他们使用word2vec将知识单元中的单词向量化, 然后利用卷积神经网络预测两个知识单元之间的相关性.Guo等人[29]将word2vec应用于可追踪性链恢复领域.由于传统的可追踪性链恢复方法都是基于信息检索的方式, 很难将深层次的语义知识和领域知识融入到追踪链的建立过程中, 因此, 他们利用word2vec技术建模软件需求文档与实现文档中的深层次语义和领域知识, 然后使用循环神经网络学习需求文档与实现文档在语义层面的信息, 最终生成需求文档与实现间的可追踪性链.软件文档与代码之间存在的语义鸿沟是基于搜索的软件工程中面临的巨大挑战, Ye等人[30]首先利用word2vec技术将软件文档与代码映射到同一个向量空间中, 然后再计算软件文档与代码之间的语义相似度.他们的方法在基于搜索的代码漏洞定位中表现出良好的效果.除此之外, 为了协助中文用户能顺利使用开发者问答社区, 有学者利用word2vec和卷积神经网络将中文问题翻译为对应的英文问题[31].程序员在修复相似的代码漏洞时往往具有更高的效率, 因此, 有学者将word2vec技术应用于相似代码漏洞推荐上[32].他们使用word2vec将与漏洞描述相关的所有信息进行词向量化, 然后计算任意代码漏洞之间的相似性.

6.3 代码注释相关的研究和实践

高质量的代码注释可以很好地用于程序理解和代码维护等实践活动中.目前, 与代码注释相关的实践和研究主要关注2方面的问题:代码注释质量评估与代码注释自动生成.

很多学者提出了各种各样的方法用于评估代码中的注释质量.据我们所知, 最早关于注释质量评估的方法可以追溯到1992年[7], Oman等人最先通过计算源代码中注释所占的比例来评估代码注释质量.显然, 他们的方法是不够精确和严谨的.随后, Steidl等人[2]提出了一种基于机器学习的方法用于评估注释质量, 他们的方法基于一系列简单的评判标准, 比如注释的有用性、完整性等, 然后使用决策树来判别注释质量.Khamis等人[3]开发了一个注释质量评价工具——JavadocMiner, 他们的工具基于一套启发式算法实现, 比如代码与注释的关联性等.除此之外, Storey等人[33]都在源代码中的注释上做了实证研究, 他们的研究结果揭示了代码注释在软件开发过程中是如何支持各种软件活动的.

自动地生成代码注释是研究人员一直追求的目标.Wong等人[34]提出了一种从StackOverflow上挖掘大规模问答数据来自动生成代码注释的方法.他们的方法计算输入代码片段和StackOverflow上的代码片段之间的相似性, 并将StackOverflow上的代码片段的描述用于生成输入代码片段的注释.之后, Wong等人[35]又提出了另一种通过挖掘现有软件代码库自动生成代码注释的方法.他们使用代码克隆检测技术从软件代码库中发现语法相似的代码片段, 并将代码注释应用于其他语法类似的代码片段上.此外, Sridhara等人[5]提出了一种新颖的方法用来生成Java方法的注释.给定一个方法的签名和方法体, 他们的方法可以自动生成注释用于描述该方法的动作.Moreno等人[6]提出了一种生成Java类注释的方法, 他们方法生成的注释主要描述了类本身涵盖的内容以及该类所起的作用.

目前, 与代码注释相关的研究大部分都是关于注释质量评估和注释自动生成的, 而没有直接与注释决策支持相关的.有学者提出了代码日志决策支持方法[36], 他们的方法与我们的方法有类似之处.但是不同之处在于:他们的方法仅仅是告知编程人员一段代码是否需要添加日志, 而我们的方法是告知编程人员需要在代码中何处添加注释.

7 结论

代码注释在程序理解和软件维护中扮演着极其重要的角色, 恰当的代码注释决策成为了软件编程人员追求的目标.文章提出了一种新颖的CommentAdviser方法用以辅助软件编程人员在代码开发过程中做出恰当的注释决策.CommentAdviser从当前代码行的上下文代码中提取代码结构特征以及代码语义特征作为支持注释决策的主要依据, 然后利用机器学习算法判定当前代码需要添加注释的可能性.在GitHub中的10个数据集上评估了提出的方法, 实验结果表明了CommentAdviser的可行性和有效性.在未来的研究工作中, 我们将从当前代码行的上下文代码语法分布入手, 加入更多的可判别特征, 进一步提高CommentAdviser的精确度和召回率.同时, 我们打算将CommentAdviser方法嵌入到IDE中.开发人员编写代码的同时, CommentAdviser向其提供注释决策建议.

参考文献
[1]
Tenny T. Program readability:Procedures versus comments. IEEE Trans. on Software Engineering, 1988, 14(9): 1271–1279. [doi:10.1109/32.6171]
[2]
Steidl D, Hummel B, Juergens E. Quality analysis of source code comments. In: Proc. of the 21st Int'l Conf. on Program Comprehension. 2013. 83-92.
[3]
Khamis N, Witte R, Rilling J. Automatic quality assessment of source code comments: The JavadocMiner. In: Proc. of the Int'l Conf. on Natural Language Processing and Information Systems. 2010. 68-79.
[4]
Fluri B, Wursch M, Gall HC. Do code and comments co-evolve? On the relation between source code and comment changes. In: Proc. of the 14th Int'l Conf. on Working Conf. on Reverse Engineering. 2007. 70-79.
[5]
Sridhara G, Hill E, Muppaneni D, Pollock L, Vijay-Shanker K. Towards automatically generating summary comments for Java methods. In: Proc. of the Int'l Conf. on Automated Software Engineering. 2010. 43-52.
[6]
Moreno L, Aponte J, Sridhara G. Marcus A, Pollock L, Vijay-Shanker K. Automatic generation of natural language summaries for Java classes, [C]. of the 21st Int'l Conf. on Program Comprehension., 2013: 23–32. http://ieeexplore.ieee.org/document/6613830
[7]
Oman P, Hagemeister J. Metrics for assessing a software system's maintainability. In: Proc. of the Int'l Conf. on Software Maintenance. 1992. 337-344.
[8]
Dit B, Holtzhauer A, Poshyvanyk D, Kagdi HH. A dataset from change history to support evaluation of software maintenance tasks. In: Proc. of the Int'l Conf. on Mining Software Repositories. 2013. 131-134.
[9]
Huang Y, Chen XP, Liu ZY, Luo XN, Zheng ZB. Using discriminative feature in software entities for relevance identification of code changes. Journal of Software:Evolution and Process, 2017, 29(7): e1859. [doi:10.1002/smr.v29.7]
[10]
Huang Y, Zheng. QY, Chen XP, Xiong YF, Liu ZY, Luo XN. Mining version control system for automatically generating commit comment. In: Proc. of the 11th Int'l Conf. on Empirical Software Engineering and Measurement. 2017.
[11]
Zhang J, Chen JJ, Hao D, Xiong YF, Xie B, Zhang L, Mei H. Search-Based inference of polynomial metamorphic relations. In: Proc. of the 29th Int'l Conf. on Automated Software Engineering. IEEE/ACM Press, 2014. 701-712.
[12]
Gosling J, Joy B, Steele G, Bracha G, Buckley A. The Java language specification. Java se 8th ed., 2014.
[13]
Vermeulen A, Ambler SW, Bumgardner EMG, Misfeldt T, Shur J, Thompson P. The Elements of Java Style. Cambridge: Cambridge University Press, 2000.
[14]
Mou LL, Li G, Zhang L, Wang T, Jin Z. Convolutional neural networks over tree structures for programming language processing. In: Proc. of the 30th Int'l Conf. on Artificial Intelligence. 2016. 1287-1293.
[15]
Beniamini G, Gingichashvili S, Orbach AK, Feitelson DG. Meaningful identifier names: The case of singleletter variables. In: Proc. of the 25th Int'l Conf. on Program Comprehension. 2017. 45-54.
[16]
Mikolov T, Sutskever I, Chen K, Corrado G, Dean J. Distributed representations of words and phrases and their compositionality. In: Proc. of the 26th Int'l Conf. on Neural Information Processing Systems. 2013. 3111-3119.
[17]
Aggarwal CC, Zhai C. A survey of text classification algorithms. In: Proc. of the Mining Text Data. Springer-Verlag, 2012. 163-222.
[18]
Hall M, Frank E, Holmes G, Pfahringer B, Reutemann P, Witten IH. The weka data mining software:An update. SIGKDD Explorations Newsletter, 2009, 11(1): 10–18. [doi:10.1145/1656274]
[19]
Chawla NV, Bowyer KW, Hall LO, Kegelmeyer WP. Smote:Synthetic minority over-sampling technique. Journal of Artificial Intelligence Research, 2002, 16(1): 321–357. http://dl.acm.org/citation.cfm?id=1622416
[20]
Kim SH, Zhang HY, Wu RX, Gong L. Dealing with noise in defect prediction. In: Proc. of the 33th Int'l Conf. on Software Engineering. 2011. 481-490.
[21]
Dyer R, Rajan H, Nguyen HA, Nguyen TN. Mining billions of ast nodes to study actual and potential usage of java language features. In: Proc. of the 36th Int'l Conf. on Software Engineering. 2014. 779-790.
[22]
White M, Tufano M, Vendome C, Poshyvanyk D. Deep learning code fragments for code clone detection. In: Proc. of the 31st Int'l Conf. on Automated Software Engineering. 2016. 87-98.
[23]
Wang S, Liu TY, Tan L. Automatically learning semantic features for defect prediction. In: Proc. of the 38th Int'l Conf. on Software Engineering. 2016. 297-308.
[24]
Gao Q, Zhang HS, Wang J, Xiong YF, Zhang L, Mei H. Fixing recurring crash bugs via analyzing q&a sites (t). In: Proc. of the 30th Int'l Conf. on Automated Software Engineering. 2015. 307-318.
[25]
Nguyen AT, Nguyen TN. Graph-Based statistical language model for code. In: Proc. of the 37th Int'l Conf. on Software Engineering. 2015. 858-868.
[26]
Negara S, Codoban M, Dig D, Johnson RE. Mining fine-grained code changes to detect unknown change patterns. In: Proc. of the 36th Int'l Conf. on Software Engineering. 2014. 803-813.
[27]
Jiang QT, Peng X, Wang H, Xing ZC, Zhao WY. Summarizing evolutionary trajectory by grouping and aggregating relevant code changes. In: Proc. of the 22nd Int'l Conf. on Software Analysis, Evolution, and Reengineering. 2015. 361-370.
[28]
Xu BW, Ye DH, Xing ZC, Xia X, Chen GB, Li SP. Predicting semantically linkable knowledge in developer online forums via convolutional neural network. In: Proc. of the 31st Int'l Conf. on Automated Software Engineering. 2016. 51-62.
[29]
Guo J, Cheng JH, Cleland-Huang J. Semantically enhanced software traceability using deep learning techniques. In: Proc. of the 39th Int'l Conf. on Software Engineering. 2017. 3-14.
[30]
Ye X, Shen H, Ma X, Bunescu R, Liu C. From word embeddings to document similarities for improved information retrieval in software engineering. In: Proc. of the 38th Int'l Conf. on Software Engineering. 2016. 404-415.
[31]
Chen GB, Chen CY, Xing ZC, Xu BW. Learning a dual-language vector space for domain-specific cross-lingual question retrieval. In: Proc. of the 31st Int'l Conf. on Automated Software Engineering. 2016. 744-755.
[32]
Yang XL, Lo D, Xia X, Bao LF, Sun JL. Combining word embedding with information retrieval to recommend similar bug reports. In: Proc. of the 27th Int'l Conf. on Software Reliability Engineering. 2016. 127-137.
[33]
Storey MA, Ryall J, Bull RI, Myers D, Singer J. Todo or to bug: Exploring how task annotations play a role in the work practices of software developers. In: Proc. of the 30th Int'l Conf. on Software Engineering. 2008. 251-260.
[34]
Wong E, Yang JQ, Tan L. Autocomment: Mining question and answer sites for automatic comment generation. In: Proc. of the 28th Int'l Conf. on Automated Software Engineering. 2013. 562-567.
[35]
Wong E, Liu TY, Tan L. Clocom: Mining existing source code for automatic comment generation. In: Proc. of the 22nd Int'l Conf. on Software Analysis, Evolution, and Reengineering. 2015. 380-389.
[36]
Zhu JM, He PJ, Fu Q, Zhang HY, Lyu MR, Zhang DM. Learning to log: Helping developers make informed logging decisions. In: Proc. of the 37th Int'l Conf. on Software Engineering. 2015. 415-425.