分享一篇来自IEEE Transactions on Software Engineering 22的论文,题目为”DeepLineDP: Towards a Deep Learning Approach for Line-Level Defect Prediction“。论文模型已开源:https://github.com/awsm-research/DeepLineDP。
目前软件缺陷预测研究主要存在两个限制:(1)检测粒度较粗,(2)代码token周围的代码行没有被充分利用。
对于限制(1):目前的缺陷预测在不同粒度上都有研究,如:包,组件,文件和方法。但存在一个事实:一个存在缺陷的文件中,并不是所有的代码行都与缺陷有关。这大大影响了开发人员检查缺陷的效率。
对于限制(2):源代码具有层次结构,出现在不同行中的相同代码token根据其位置可能具有不同的含义。
在本文中,作者进行了一项调查以了解工程师们是如何在代码评审过程中执行代码检查,以及他们对行级缺陷预测的看法。根据36位工程师的反馈,作者发现他们中的50%花了至少10分钟到1个多小时来审查一个文件,而他们中的64%仍然认为代码检查活动具有挑战性。调查结果如图1所示。
Fig. 1 36位受访者参与调查的结果总结
对调查结果进行分析后,作者发现:
(1)开发人员按照自上而下的顺序检查源代码。一旦识别出有缺陷的行,他们将检查方法调用和它们周围的行。每个文件通常需要至少10分钟到一个多小时
(2)64%的受访者认为行级缺陷预测工具可能有助于识别有缺陷的代码行,因为:
-
能够减少代码审查的时间;
-
如图2的检测结果示例可知,检测结果很容易理解(红色高亮高危代码行);
-
能够提供有用的信息(可能存在缺陷的概率)。
Fig. 2 检测结果示例
模型框架如图3所示,包括:(1)数据准备,(2)代码预处理:进行代码抽象和语料库管理,(3)Token嵌入:将源代码转换为向量表示,(4)层次化注意力网络:学习源代码的分层结构,(5)文件级&行级缺陷预测。
Fig. 3 模型框架
(1)数据准备
数据准备部分主要是采集网络上开源的数据集以支持实验验证。
(2)代码预处理
代码预处理的目标是提取每个代码Token的语法、语义和上下文代码特征。本文使用JavaParser对Java源代码进行解析,构建AST。每一个源代码文件被解析成一组代码行,每一个代码行被解析为一个token序列。
代码预处理需要涉及语料库的管理。过大的语料库对计算资源的需求较大。在本文中,作者对语料库进行了限制,具体做法为:将整数,实数,指数符号,十六进制数替换为<num>标记,将常量字符串替换为<str>标记。同时移除特殊字符,如:”{“,”””,”‘”,空格等。此外,还需要把存在于测试集但不存在与训练集的token统一替换 为<unk>。
(3)Token嵌入
在本文中,原始代码的token以及代码行的顺序会被保留,以进一步挖掘源代码的层次结构。
首先基于Word2Vec为每一个项目构建特定于项目的词向量模型,以确保向量表示是从特定域中派生出来的。这意味着从特定领域语言模型生成的向量表示倾向于产生更有意义的向量。
(4)层次化注意力网络
图4为用于处理代码层次结构的层次化注意力网络,包含4个部分:token编码器,token级注意力层,代码行编码器,行级注意力层。
-
token编码器:对于每一个代码行,首先将其解析为一个token序列。然后将每一个token转换成向量表示。接着使用BiGRU对token序列进行处理。每一个token用BiGRU的两个方向的隐藏层输出拼接得到,。
-
token级注意力层:通过注意力机制对每一个token的表示向量进行赋值,将每一个token的BiGRU向量与其对应的注意力值进行加权求和,得到行向量。
-
代码行编码器:行向量的编码方式与token的编码方式相同。
-
行级注意力层:行级注意力层的原理与token级注意力的原理相同。
Fig. 4 用于处理代码的两层层次化注意力网络
(5)文件级&行级缺陷预测
对于文件级缺陷预测,分类器使用的是一层MLP,使用Sigmoid函数计算文件存在缺陷的概率。
对于行级缺陷预测,使用注意力得分来反应每一个token存在风险的情况。通过将token级注意力层获得的注意力得分进行降序排序,去前k个token的注意力等分值之和作为当前代码行存在风险的判断指标。本文中k设置为1500。
下面是本文涉及的数据集以及部分实验结果展示。
Tab. 1 数据集详情
Tab.2 模型在各数据集上的性能评估结果
原文始发于微信公众号(拨开云雾):一种基于深度学习的语句级缺陷预测方法