(1994-), 男, 博士生, 主要研究领域为代码理解, API补全
(1991-), 男, 博士, 助理研究员, CCF 专业会员, 主要研究领域为软件工程, 业务过程管理, 自然语言处理
(1978-), 男, 博士, 副教授, CCF 高级会员, 主要研究领域为软件工程, 分布式计算与边缘计算, 业务过程管理, 自然语言处理
(1967-), 男, 博士, 教授, 博士生导师, CCF 杰出会员, 主要研究领域为软件工程, 人工智能
近年来, 随着软件技术在各行各业、不同领域的应用不断扩展与深入, 同时伴随着软件架构、服务计算等技术的不断发展, 软件行业涌现出了功能丰富且规模庞大的第三方API或库, 软件开发者在实现软件功能的时候也越来越依赖这些API. 但学习这些API的使用是非常困难且耗时的, 主要有两方面的原因: 1)相关文档的缺失和错误; 2)相关API用法的示例代码较少. 因此, 研究自动的API补全方法以帮助开发人员在开发过程中正确且快速的使用API, 具有很大的应用价值. 然而, 现有API自动补全方案多数将待补全代码段看作纯文本, 忽略了API所属对象类型对预测API的影响. 为此, 探究了对象类型对补全API的作用, 并且在对象状态图的启发下, 设计了一种使用API所属对象的类型作为特征的补全方法. 具体而言, 首先从API调用序列中先抽取同一对象类型的子序列, 利用深度学习模型编码出每个对象的状态, 再利用对象状态生成整个方法块的状态表示进行补全. 为了验证提出的补全方法, 在6个流行Java项目上进行了验证. 实验结果证明, 提出的考虑对象类型的API补全方法在预测准确率上明显高于基线模型.
In recent years, with the continuous expansion and deepening of the application of software technology in various industries and fields, as well as the development of software architecture, services computing, etc., the software industry has emerged with feature-rich and large-scale third-party APIs or Libraries. Software developers are increasingly relying on these APIs when implementing software functions. However, learning the usage of these APIs is very difficult and time-consuming. There are two main reasons: 1) missing or wrong documents; 2) few sample codes for API usage. Therefore, designing automatic API completion methods to help developers use the API correctly and quickly has great application value. However, most of the existing API automatic completion methods regard the code segments to be completed as plain text, ignore the impact of the object types of APIs. Therefore, this study explores the role of the object types in completing APIs. Besides, inspired by the object state diagram, an concrete API completion method is designed and implemented that uses the types of the objects as a novel feature. Specifically, the subsequence of the same object type is first extracted from the API call sequence and a deep learning model is used to encode the state of each object. Then, the objects’ states is used to generate a state representation of the entire method block. In order to evaluate the proposed method, comprehensive experiments are conducted on six popular java projects. The experimental results prove that the proposed API completion method achieves significantly higher predicting accuracy than the baseline approaches.
在软件开发过程中, 为了避免重复工作, 提高软件开发效率, 软件开发者通常会使用一些第三方的API(application programming interface), 即应用编程接口, 来协助完成软件的功能. 这些第三方库(Library)的API通过提供对象、方法以及变量来让软件开发者调用, 借以实现一系列特定需求或功能[
然而, 学会正确地使用这些API需要耗费软件开发者大量的时间. 一部分原因是因为这些第三方库在不断更新迭代, 另外API说明文档的缺失或者出错也使得学习成本增加[
为了帮助软件开发者正确且快捷地使用这些第三方API, 一系列API方法补全工具应运而生. API方法补全是指当程序员已经拼写出一个对象名之后, 通过查询这个对象所属类别列出所有的方法供程序员选择.
An example of auto API completion in IDEA
IDEA中智能补全API的例子
API自动补全的意义可以总结为以下几点.
1) 避免开发人员需要记住每个API的用法. 由于目前第三方API的数量已经非常庞大, 即使编程经验丰富的开发人员也几乎不可能记住每个API的具体用法. 举例来说, 当一个开发人员需要在Java代码中比较两个字符串的是否相似(忽略大小写). 他应该调用String对象中的equalsIgnoreCase这个API来完成这个任务, 但是很有可能他不记得这个API的全称. 当他在一个String类型的对象后输入点(.), API补全系统会按照当前代码上下文, 分析String对象中每个API在这里使用的可能性, 排序展示给开发人员. 假设API补全系统已经学习到equalsIgnoreCase这个API的用法, 系统会将这个API排名在靠前的位置返回给开发人员. 开发人员可以轻松找到这个API, 并利用它来实现代码功能.
2) 帮助开发人员书写错误更少的代码. API补全系统只会返回目标对象中已有的API供用户选择, 这可以保证补全结果至少在语法上正确. 比如用户需要系统对java.swing包中的JFrame对象进行补全, 系统只会分析JFrame中已有的API来推荐给用户. 这可以保证不会推荐生成无法编译的代码.
3) 加快开发人员书写代码的速度. 为了帮助开发人员更容易理解API的用法, API的名称通常体现了一部分这个API的功能描述. 这也造成有些API的名称可能过于复杂, 人工输入这些API的名称非常费时. API补全系统可以帮助开发人员补全API方法的调用, 而无需要开发人员手动输入, 这可以加速代码书写速度. 有些API补全工具甚至可以支持多行补全, 比如自动补全try-catch 结构块[
4) 代码复用. 开发人员为了避免重复开发, 通常使用复制、粘贴的方式来复用相关代码. 这种方式也被称作代码克隆(code clone). 有研究表明, 软件系统中克隆代码的比例通常在15%–25%之间[
为了满足开发人员实际编程需要, 提供切实可用的API方法补全, 本文的主要研究目标在于设计和实现一个考虑对象特征的API补全技术, 同时实现一个支持离线和在线的集成开发环境插件, 提供API方法补全服务.
本文的主要研究内容包含3部分: 一是从代码库中构建高质量的API调用序列; 二是研究利用对象信息的API补全技术; 三是支持离线和在线的API 补全集成开发环境插件.
Bruch等人[
Proksh等人[
Heinemann等人[
Nguyen等人[
使用统计语言模型的API补全方法将代码看作一种语言, 通过语言模型对代码或者从代码提取的API调用序列建模. Akbar等人[
Nguyen等人[
还有使用深度学习模型实现API补全任务的工作. 例如, Rayche等人[
另外, 由于代码中存在大量自定义的方法名和变量名, 这些词无法使用词表进行记录, 而这些词在实际API补全中具有重要意义[
长短期记忆模型 [
这个函数可以把输入值规划到0–1之间. 0表示门关闭, 即任何信息都不传送; 1表示门打开, 任何信息都会被传送; 其他值表示以一定的比例将信息传送入门内. LSTM设计了3个门: 输入门、输出门和遗忘门. 3个门的计算方式如下:
其中,
其中,
注意力机制是由Chorowski等人为机器翻译提出的[
其中, 第1种方式是直接将查询向量与目标词进行点积, 点积结果越大表示对该词给予越多的关注. 第2种方式与第1种方式类似, 只是因为点积需要
通过使用注意力机制, 模型可以动态地关注有助于执行当前任务的输入的某些部分, 将这种相关性概念结合起来. 神经网络中注意力机制快速发展的原因主要有3点. 首先, 它可以被应用于多种类型的任务中, 比如机器翻译[
为了解决API补全的问题, 本节首先给出了相应的问题定义, 并基于问题描述进行建模.
问题: API自动补全.
条件: (1)待补全的方法块, 以及(2)待补全位置和待补全位置的对象类型.
目标: 对待补全位置推荐可能的API调用.
对于API补全问题, 首先确定代码方法块的待补全位置, 并利用静态分析技术抽取出方法中的API调用, 构建API调用序列. 如
Model API completion problem
API补全问题建模
本文研究的方法是基于API调用序列的API补全模型. 现有的使用API调用序列进行补全的模型[
Java code of implementing http request using HttpClient
使用HttpClient实现http请求的Java代码
从
Control flow graph of http request
http请求的数据控制流图
那么, 为什么API调用序列会有这种部分有序性的特点呢?其主要原因是由于面向对象语言具有封装性, 即对象行为(方法调用)原则上只能改变对象内部属性(私有变量). 也就是说, API的调用(API也是一种特殊的公开的方法)只能改变其所属对象的属性, 从而引起其所属对象的状态发生改变, 并不会影响到其他对象状态. 比如, RequestConfig.custom和HttpGet.init之间并没有顺序关系, 因为它们影响的只是各自所属对象的状态, 互相之间并没有干扰. 但是, 如果简单地认为不同对象的API调用之间毫无关系, 那也过于武断了. 比如RequestConfig.build和HttpGet.setConfig这两个不同对象的API之间就存在明显的顺序关系, 这又是因为什么呢?
先设想这样一个例子: 多媒体播放有且仅有两个API: 播放视频playVideo以及播放音乐playMusic. 通常情况下, 播放视频playVideo这个API调用的频数多一些, 不妨假设调用playVideo和playMusic的概率分别为0.8和0.2. 但如果代码上下文已经有另一个对象调用了指定音乐源这个API, 那么此时显然调用playMusic这个API更加合理. 这是因为上下文相关的API调用概率实质上是一个条件概率, 在这个例子中就是已知音乐源情况下的调用概率, 即
基于这种思路, 本文设计了一种新的处理API调用序列的方式, 如
Different approach analyzing API call sequence
分析API调用序列的不同方式
基于对象类型的API补全模型整体框架图如
Overall architecture of API completion process
API补全总体框架
Architecture of API completion model
API补全模型结构图
1) 编码层: 在获取到API调用序列后, 需要先对每个API调用进行编码, 才可以将它们输入到神经网络模型中. 有两种直观的思路来对API调用序列进行编码: 一种是直接对所有的API进行编码, 即把“对象.API”这样一个结构看成是一个整体, 对这个整体进行索引, 构建词汇表. 但这样做的缺点是会忽略掉对象类型信息, 即同一个对象的API调用无法直接根据向量编码看出它们的关系. 另一个直观的思路是将“对象.API”这样一个结构拆分开, 即对对象类型和API调用分别编码, 并把它们各自当作一个时间节点, 以“对象类型->API调用-> 对象类型->API调用…”这样一种形式的序列输入到神经网络中. 这样做的好处是可以让模型显性地知道当前API的对象类型, 但是这样做会导致原本的序列长度会扩张成原有长度的两倍. 而序列模型, 包括长短期记忆模型, 其实都不适合用来处理长度过长的序列, 因此这样做的效果并不好.
在本模型中, 本文使用了两个词嵌入矩阵
分别对对象类型和API进行编码, 然后将这两个词向量表示拼接在一起, 得到时间
这样就可以在不改变输入序列长度的情况下, 显式地告知模型同一个对象内API调用的联系. 因为若两个API调用属于同一个对象, 那这两个API调用对应的编码前一半是一样的. 同时, 因为空缺位置的API调用是未知的, 本文使用“hole”来表示空缺位置的API调用. “hole”一词在API编码时被当作一个特殊的API, 它在API词汇表中的序号是1 (0是UNK, 表示不在词汇表的API调用). 举例来说,
2) 层级网络层: 层级网络(hierarchical network)主要应用于自然语言处理中文本摘要领域. 由于文本信息天然具有层级性: 词构成句, 句构成文章. 因此通常的做法是先由词提取出句子级别的特征, 再基于句子级别的特征提取出整篇文章的重点信息. 本文的思想与之类似, 如果将词映射为API调用, 句子特征映射为对象状态. 对象状态可以从属于该对象的API调用中提取, 而整个方法的特征可以从全部对象状态中提取.
首先在对象层, 根据空缺位置将API调用序列划分为3部分: 空缺位置之前的API调用, 空缺位以及空缺位置之后的API调用. 对于空缺位置之前的API调用, 先按照对象类型抽取出同属于一个对象的API调用子序列, 并将每个调用子序列使用LSTM来编码对象状态, 编码对象状态过程如公式(7)所示:
其中,
接下来需要获取整个API调用序列对应的方法状态. 由于空缺位置不确定, 因此需要设计一个空缺位置感知的网络模型来编码对象状态. 同时根据程序局部性原理, 模型应当更加关注空缺位置周围的对象状态. 本文设计了一个双向的LSTM来解决这一问题. 对于空缺位置和空缺位置之前的对象状态序列, 将它输入到一个正向的LSTM模型中, 得到空缺位置之前的方法状态
3) 预测层:上一小节中介绍了如何利用对象信息对API序列进行编码的过程, 本节将介绍如何利用序列编码进行空缺位置补全. 常见的预测补全位置API的方法是将方法状态输入到一个与维度等同于全体API的全连接网络中, 再将结果输入到Softmax层, 概率最大的位置对应的API即最终推荐的补全API. 但是, 这样做有两个缺点: 首先, 全体API的数量非常大, 在本文的数据集中, 全体API的数量是35380个, 这意味着需要使用一个十分庞大的全连接网络来进行预测, 继而引发内存占用和时间效率的问题. 另一方面, 由于空缺位置对象类型已知, 不属于该类型的API不应该被推荐, 否则会导致程序语法错误. 因此本文设计了一个基于补全位置对象类型的预测机制.
首先, 根据空缺位置对象类型确定API候选集. 因为空缺位置对象类型已知, 不属于该对象的API不可能被调用, 因此可以根据对象类型中的全部API确定调用候选集. 但是这会引起另一个问题, 因为每个对象类型中的API数量不固定, 这意味着不同对象类型的补全对应的概率输出维度也不相同. 本文采用了类似于Word2Vec[
其中,
本文设计和执行了全面的对比实验, 并通过回答如下研究问题以验证本文提出的基于对象类型的API补全技术有效性.
问题1: 基于对象类型的API补全技术与当前先进的补全方法相比准确率以及性能如何?
问题2: 基于对象类型的API补全技术在不同补全位置下性能如何?
问题3: 基于对象类型的API补全技术在不同对象个数下性能如何?
问题4: 基于对象类型的API补全技术各组件是否均对补全产生帮助?
数据集: 本实验采用的训练集是使用爬虫程序从Github上按照star数爬取的前15 000个Java项目. 在分析数据时, 我们发现其中有一部分项目属于教程, 即项目中是对某些技术的介绍, 其中并不包含Java代码. 在过滤掉这一部分项目后, 最终我们得到了14 785个Java项目. 通过对项目中源文件抽取出API调用序列, 再过滤掉序列长度小于2的数据, 最终我们获得了1 130 203条API调用序列. 测试集使用Galaxy、Log4j、JGit、Itext、FroyoEmail和Grid-Sphere. 这6个项目在之前的工作中也被用来当作测试集来使用[
Description of data set
数据集描述
训练集 | 项目个数 | 代码行数 | API序列个数 | API序列平均长度 | 类个数 | API个数 |
值 | 14 785 | 352 312 696 | 1 130 203 | 4 | 5 084 | 35 380 |
测试集 | Galaxy | Log4j | JGit | Itext | FroyoEmail | Grid-Sphere |
API序列个数 | 209 | 829 | 2 256 | 1 546 | 566 | 683 |
评估标准: 本文使用了两种验证维度来验证模型效果: Top-K ACC和MRR (mean reciprocal rank)[
其中,
它表示如果真实标签在推荐结果中的次序小于
它表示如果真实标签在推荐列表中的第1个匹配, 分数为1, 第2个匹配的分数为0.5, 第
Statistical chart of API seq length in test dataset
测试集不同项目API序列长度统计图
基线模型:本文使用了4个基准模型来与本文提出的模型进行对比实验, 包括: N-gram [
N-gram模型使用了两个模型的联合概率来对API进行补全. 全局模型(global model)是使用外部代码库训练的N-gram语法模型, 本地模型(local model)是基于该项目下所有源代码文件训练得到的语法模型. 在需要对一处API空缺进行补全时, 利用空缺位置周围
HAPI模型是使用一个隐马尔可夫模型来进行API补全推荐. 其主要思想是将对象状态当作隐藏状态, 将API调用当作观测序列. 使用一个隐马尔可夫模型来刻画API调用过程. 因为它本身提出是为了分析Android源代码中的API调用. 本文重新实现了这个模型, 并为训练集中的5 084个对象类型每个训练了一个隐马尔可夫模型. 同时为训练集中在方法块中共现超过200次的对象类型额外训练了它们对应的多对象隐马尔可夫模型. 在验证模型性能时, 本文没有分开验证单对象隐马尔可夫模型和多对象隐马尔可夫模型的性能. 而是先寻找是否有包含API序列中所有对象类型的模型, 如果有, 直接调用. 如果没有, 寻找包含序列中对象类型集合的最大子集的模型. 在预测时, 优先使用包含对象类型最多的模型. 如果存在多个包含一样多对象类型的模型, 我们使用这些模型的预测概率计算其联合概率, 使用联合概率推荐补全.
LSTM是Dam在2016年提出的代码补全模型. 因为原文是将源代码直接作为文本序列输入到LSTM中, 为了对比实验的数据源统一性, 本文重新实现了该模型并将输入改为了API调用序列.
APIHelper是Yan在2018年提出的API补全模型. 他们在标准LSTM模型基础上, 使用了拼接编码以及确定的负采样算法. 拼接编码与本文类似, 是将对象类型和API调用分开编码后拼接成最终的向量表示. 确定的负采样算法是让模型在训练时不需要对全体API计算推荐概率, 而是对采样出的负样本和真实标签计算概率, 进而提升模型的收敛速度. 确定的意思是指不同于标准的随机采样算法, 负样本选择的都是属于空缺位置对象类型的API, 这样采样出的负样本都是属于该对象类型的API调用. 预测时只需要使用类似的采样算法, 选取出空缺位置对象类型的所有API进行预测.
实验环境: 本文中的实验使用了一台显卡型号为NVIDIA GeForce 2080Ti的centos服务器. 其中API序列最大长度限定为10. 词向量和隐藏状态维度均设为128. 训练使用了交叉墒作为损失函数, 学习率设为1E–3, batch size设置为32.
另外, 本文分析了模型在预测时的时间效率和空间占用率. 考虑到很多用户私人笔记本中显卡配置并不高, 因此在进行预测对比实验时, 所有使用深度学习的模型均使用内存加载进行预测. 全部模型的预测时间和内存占用如
Comparison of Top-K Accuracy in different projects
不同项目中Top-K Accuracy变化曲线
Comparison of MRR in 6 test projects
不同模型在6个测试项目上的MRR对比
模型 | JGit | Log4j | Itext | Grid-Sphere | Galaxy | Froyo-Email | All |
N-gram | 0.414 | 0.556 | 0.454 | 0.455 | 0.415 | 0.37 | 0.422 |
LSTM | 0.432 | 0.614 | 0.465 | 0.474 | 0.405 | 0.387 | 0.438 |
HAPI | 0.403 | 0.503 | 0.45 | 0.514 | 0.564 | 0.544 | |
APIHelper | 0.594 | 0.667 | 0.551 | 0.583 | 0.549 | 0.546 | 0.57 |
Ours | 0.66 |
Comparison of MRR in 6 test projects
不同模型的性能对比
模型 | 内存占用 (MB) | 预测时间 (ms) |
N-gram | 182 | 21 |
LSTM | 48.5 | 73 |
HAPI | 328 | 20 |
APIHelper | 356 | 13.5 |
Ours |
本节主要分析补全位置对模型预测准确率的影响. 通过将测试集按照API调用序列空缺位置对数据进行划分. 空缺位置出现在序列前1/5位置的, 标记为第1类; 出现在1/5~2/5位置的标记为第2类. 以此类推, 将整个测试集划分为5部分.
从
总体来看, 本文提出的模型预测性能不会过多受到补全位置的影响, 一直保持着较高的水平. 而基线模型的预测效果会随着补全位置的不同而产生波动. 因为模型最终的应用场景是在开发环境中提供持续的API补全服务, 也就是说空缺位置不断发生变化. 从该试验可以看出, 本文提出的模型可以在不同位置下一直提供较高质量的补全性能, 相较于基线模型可以为开发人员提供更好的补全体验.
本小节讨论了API序列中对象个数对模型性能的影响.
Impact of the hole location on the performance of different models
待补全位置对不同模型的性能影响
Impact of the object num on the performance of different models
API序列中对象个数对模型性能的影响
总体来看, 由于不是所有出现的对象都会影响空缺位置API调用, 因此API序列中对象个数并不会对除Nested-Cache N-Gram以外的模型造成影响. 因为其他模型都使用了各自的策略来减少无关对象的API调用对补全效果的影响. 其中, HAPI使用了统计的方法来过滤掉无关对象的调用, 本文提出的模型、APIHelper和LSTM由于都是用了长短期记忆模型来“遗忘”掉无关调用. 由于Nested-Cache N-Gram仅仅会考虑空缺位置周边的
本小节介绍本文提出的基于对象类型的API补全模型各个组件的作用.
the model disassembly experiment
模型拆解实验
拆解模型 | JGit | Log4j | Itext | Grid-Sphere | Galaxy | Froyo-Email |
-拼接编码 | 0.55 | 0.62 | 0.53 | 0.52 | 0.48 | 0.54 |
-对象层 | 0.59 | 0.66 | 0.55 | 0.58 | 0.54 | 0.56 |
-方法层 | 0.57 | 0.65 | 0.57 | 0.59 | 0.52 | 0.57 |
-候选集策略 | 0.43 | 0.61 | 0.46 | 0.47 | 0.40 | 0.42 |
因此可以得出结论, 本文提出的模型各个组件, 包括API拼接编码层、对象状态编码层、方法状态编码层以及使用候选集的预测层均可以提升模型的补全效果, 缺失了任何一部分都会造成模型补全性能的下降.
本文提出的方法是使用对象类型信息来帮助API补全, 但对于一些没有对象概念的编程语言, 比如C语言, 或是操作系统内核相关API, 并不能直接使用本文提出的方法. 一种可行的解决方案是将所有API当作属于同一个对象类型的API, 这样等价于直接使用一个双向LSTM模型来进行补全. 另一种方案是将API所在文件的名称作为对象类型, 比如C语言中的头文件信息. 但这种方案会存在一定的缺陷, 因为同一个文件下的API可能并没有关系, 也不能构成对象的概念. 比如C语言中math.h下的API只是实现数学功能的API的集合, 将这个文件作为对象是不合理的. 当然, 如果API所在文件具有对象的部分特征, 比如文件流fstream或者输入输出流iostream, 将API所在文件看作对象类型也具有一定的合理性.
除此之外, 由于本方法需要获取变量的对象类型信息, 并从待补全代码中提取API调用序列, 这使得本方法需要对代码进行静态分析, 这会导致一定的时间和空间开销, 速度上可能不如一些将代码作为纯文本进行分析补全的方法, 但本文的方法可以保证推荐补全的API不会有语法错误, 这是将代码作为纯文本分析的方法做不到的.
本小节分析了两个真实的补全场景, 如
the examples of API completion
API补全实例
待补全代码 | public void read_file(String filename) throws Exception{
|
正确补全 | bufferedReader.close() |
IDEA
|
bufferedReader.readLine()
|
APIHelper
|
bufferedReader.close() 61.99%
|
Ours
|
bufferedReader.close() 79.73%
|
待补全代码 | public void read_file(String filename) throws Exception{
|
正确补全 | bufferedReader.close() |
IDEA
|
bufferedReader.readLine()
|
APIHelper
|
bufferedReader.readLine() 28.56%
|
Ours
|
bufferedReader.close() 98.36%
|
本文实现了一个基于IDEA的自动补全插件, 支持离线和在线补全. 整体框架采用了使用B/S结构, 并使用分层结构对补全系统进行了相应设计. 依次划分为客户端应用层、服务器控制和计算层以及服务器数据存储层. 如
Architecture of API completion system
API补全系统框架图
客户端应用层是基于IDEA插件开发. 主要实现了API补全系统与用户交互的功能, 包括触发器组件, API列表展示组件以及自动补全组件. 同时, 系统将代码分析组件放在了客户端本地进行分析, 这主要是出于对用户隐私和服务器性能的考虑. 客户端应用层还提供了一个本地模型预测组件, 用于让用户本地加载模型, 离线实现补全功能.
服务器控制和计算层主要是包括两部分功能: 一是为在线API补全提供服务支持, 二是记录用户使用补全服务时传入的真实待补全API序列以及最终选择的补全API. 为了支持多人同时使用在线补全服务, 本文在该层设计了一个请求缓存组件, 来将用户请求缓存入优先队列中, 然后按批次取出一起放入模型进行预测. 另外, 在用户完成了一次补全服务后, 会调用请求处理组件存储本次服务对应的空缺API序列和最终补全结果, 用于之后进一步的模型分析和优化.
服务器数据存储层主要实现缓存请求数据和存储真实补全样例的功能. 存储层使用了Mysql数据库来存储真实补全样例, 使用Redis数据库来缓存用户请求.
Configuration of API completion plugin
API补全插件配置图
在正确的配置了API补全服务后, 用户可以使用插件来调用API补全服务.
An example of API completion plugin
插件补全效果展示图
本文针对现有API补全方案中忽略API所属对象类型的问题, 探究了对象类型对API补全效果的影响, 并创新性地设计了一种使用待补全代码段中对象类型作为额外特征的API补全方法, 该方法的核心是一个包含4个层级的深度学习模型: 输入层、编码层、层级网络层和预测层. 具体而言, 在输入层先从待补全代码段的API调用序列中抽取出属于同一对象类型的API调用子序列; 在编码层先分别为对象类型和API编码, 然后拼接; 层级网络层的核心是两层LSTM网络, 第1层是一系列LSTM模型, 每一种对象类型对应一个LSTM, 其输入是编码层拼接好的向量表示, 第1层各LSTM的隐藏状态作为对象类型的向量表示输入第2层LSTM, 其最后的输出作为待补全代码块的向量表示; 最后预测层结合代码块向量表示和候选API的向量表示计算每一个候选API的作为正确结果的概率. 实验结果表明, 本文提出的方法在补全准确率以及效率上均优于基线模型.
本文提出的基于对象类型的API补全方法在Java编程语言上取得了一定的效果, 未来我们将继续探究其在其他类型的编程语言上的API推荐效果, 如Python、C++等. 此外, 如何在API推荐中使用代码段中更多信息作为额外特征也是本文未来重要的研究方向.
Robillard MP. What makes APIs hard to learn? Answers from developers. IEEE Software, 2009, 26(6): 27–34.
Roy CK, Cordy JR, Koschke R. Comparison and evaluation of code clone detection techniques and tools: A qualitative approach. Science of Computer Programming, 2009, 74(7): 470–495.
Akbar RJ, Omori T, Maruyama K. Mining API usage patterns by applying method categorization to improve code completion. IEICE Trans. on Information and Systems, 2014, E97-D(5): 1069–1083.
Hu S, Xiao C, Ishikawa Y. Scope-aware code completion with discriminative modeling. Journal of Information Processing, 2019, 27: 469–478.
Chen C, Peng X, Sun J, Xing ZC, Wang X, Zhao YF, Zhang HR, Zhao WY. Generative API usage code recommendation with parameter concretization. Science China Information Sciences, 2019, 62(9): 192103.
Yang YX, Chen X, Sun JG. Improve language modeling for code completion through learning general token repetition of source code with optimized memory. Int’l Journal of Software Engineering and Knowledge Engineering, 2019, 29(11–12): 1801–1818.
Hochreiter S, Schmidhuber J. Long short-term memory. Neural Computation, 1997, 9(8): 1735–1780.
Zhong H, Mei H. An empirical study on API usages. IEEE Trans. on Software Engineering, 2019, 45(4): 319–334.