一种基于程序分析和循环神经网络的代码注释生成方法与流程

文档序号:17719059发布日期:2019-05-22 02:01阅读:253来源:国知局
一种基于程序分析和循环神经网络的代码注释生成方法与流程

本发明属于软件工程技术领域,尤其涉及一种利用程序静态分析、自然语言处理、神经网络技术,为java方法自动生成代码注释的方法。



背景技术:

随着计算机应用的不断深化,软件逐渐渗透和融合到国民经济的各个领域,软件生态发生深刻变化,新的软件形态和开发模式不断涌现,其规模和数量正以惊人速度膨胀,“软件吞噬世界”这一趋势已日渐明朗,社会需求的急剧增加给现阶段的软件生产力带来的新的挑战和机遇。

大规模实证研究表明,超过60%的软件工程资源用于软件维护。软件维护是修改软件系统的过程交付后修复错误、提高性能或适应不断变化的环境。软件维护需要代码理解,作为阅读和理解的源代码是任何修改的先决条件。而程序理解耗时并且耗费大多数开发人员时间。开发人员经常使用集成开发环境、调试器和工具进行代码搜索、代码测试和程序理解,以此来减少繁琐的任务。相应的代码如果不存在伴随文档解释的话,由于代码所处情境的潜在不同,会带来额外的理解负担,甚至有可能导致代码的错误使用,从而降低开发效率,耗费软件开发和维护资源,甚至会影响后期的软件质量。文档作为软件的要素,是辅助代码理解的重要手段。在程序开发人员在使用不熟悉的代码或者应用编程接口(api)的情况下,精确的文档已成为当前影响这些代码或api可用性(usability)的关键因素。因此,如果代码缺少伴随文档解释的话,则势必会给程序员带来额外的理解负担:毕竟开发者理解代码是一项耗时的工作。对比代码规模和复杂程度迅速增加,开发人员的对程序的理解能力并没有随之同步增长,文档的重要性更加凸显,从互联网搜寻相关文档并推荐给用户可有效加快代码理解过程,从而可以间接提高软件开发生产力。然而,并非每个代码片段都有相应的摘要解释,其次,同代码搜寻推荐类似,文档亦面临海量信息,通过通用的搜索引擎很难找到直接相关的文档解释,尽管当前存在一些工具如doxygen7,javadoc等可以根据标记信息如注解(annotation)等来生成结构化文档,但其内容信息依赖于用户填写,不属于自动化代码注释生成技术范畴。因此,研究新型代码摘要生成方法,以缓解互联网大数据时代信息过载的问题,已成为当前软件开发和维护人员的迫切需求。再者,从软件工程旗舰以及领域专门会议的相关论文情况来看,每年icse,esec/fse,ase,icsme,saner及msr等都有大量代码(如api)及辅助文档生成相关的论文发表。因此,在互联网以及开源软件生态繁荣背景下的大数据时代,代码注释生成已经受到越来越多关注并已成为一个受欢迎的研究领域,除此之外,代码注释生成技术也毋庸置疑具有着重要的理论和实用价值。



技术实现要素:

针对于上述现有技术的不足,本发明的目的在于提供一种基于程序分析和循环神经网络的代码注释生成方法,以解决现有技术中在软件开发和维护过程中因为缺少代码注释而造成的程序可读性差、可理解性差、软件开发和维护成本增加的问题。本发明实现了代码注释生成的自动化,为代码生成简洁、准确的注释,提高代码的可读性和可理解性,降低代码开发和维护成本,提高代码开发和维护效率。

为达到上述目的,本发明采用的技术方案如下:

本发明的一种基于程序分析和循环神经网络的代码注释生成方法,包括步骤如下:

(1)下载java项目,构建代码库;

(2)提取java项目中每个java方法本身包含信息及其依赖信息;

(3)根据上述步骤(2)中提取到的信息,结合启发式方法对每个java方法的执行代码部分进行过滤和重构;

(4)对于java项目中的每个java方法,分析其javadoc,设定用于过滤javadoc的模板,并结合词性标注方法,对javadoc进行过滤,获得与执行代码相匹配的注释;

(5)将过滤后的代码及与其相匹配的注释组合成<代码,注释>对的集合,作为代码注释生成模型的训练集;

(6)通过步骤(5)所获取到的训练集,利用编码-解码模型,进行代码注释生成模型的训练;

(7)模型训练完成后,进行预测,给定一个java方法的执行代码部分,生成对应的注释。

进一步地,所述步骤(2)中,通过抽象语法树解析来提取java项目中每个java方法本身包含信息及其依赖信息,该抽象语法树是源代码的抽象语法结构的树状表现形式。

进一步地,所述步骤(2)中,java方法本身包含信息包括方法名、局部变量名信息、局部变量的类型信息、常量值(例如,字符串常量)及方法调用信息;java方法依赖信息包括类成员变量信息、方法调用对应的方法声明信息及限定名信息。

进一步地,所述步骤(3)中,执行代码是指实现java方法功能的程序代码。

进一步地,所述步骤(3)中,启发式方法是指设定了java方法中执行代码的替换和重构规则,用于实现常量值的替换、循环和条件结构的重构、方法调用信息的替换、变量名和变量类型的替换,以实现java方法的过滤和重构。

进一步地,所述步骤(4)中,javadoc指每个java方法对应的应用程序编程接口(api)帮助文档,其为一种具有半结构特征的文档。

进一步地,所述步骤(4)中,词性标注方法是在给定句子中判定每个词的语法范畴,确定其词性并加以标注的过程。

进一步地,所述步骤(5)中,<代码,注释>对体现java方法的代码和注释的对应关系,其作为代码注释生成模型的训练集而存在。

进一步地,所述步骤(6)中,编码-解码(encoder-decoder)模型是一种用于神经网络机器翻译的模型,编码-解码模型包含两个部分:一部分为编码器,用于将输入序列映射到一个固定维度的向量;另一部分为解码器,用于对固定维度的向量进行解码,以输出目标序列。

本发明的有益效果:

本发明主要利用程序静态分析、自然语言处理、神经网络等技术,分析、实现自动化的代码注释生成以辅助开发人员理解代码,增强代码地可读性和可理解性,减轻人工理解负担,降低软件开发和维护成本。

附图说明

图1是本发明对源代码中执行代码和javadoc进行预处理的原理图。

具体实施方式

为了便于本领域技术人员的理解,下面结合实施例与附图对本发明作进一步的说明,实施方式提及的内容并非对本发明的限定。

参照图1所示,本发明的一种基于程序分析和循环神经网络的代码注释生成方法,包括如下内容:

(1)代码库的构建

神经网络模型的训练是数据驱动的,基于本发明的最终目标是训练出一个基于神经网络的代码注释生成模型,故需要构建一个大规模的代码库来满足模型训练的需要。从开源社区github上下载6705个java项目用于构建代码库。利用抽象语法树解析所述java项目,从中提取java方法,每个java方法对应的javadoc也会被提取。

(2)代码信息提取

为java方法生成注释,代码信息是指java方法相关的信息。由于java方法并非单独存在的,因此代码信息由两部分组成:java方法本身包含信息及其依赖信息。提取方法是利用eclipsejdt的抽象语法树模块对java项目进行抽象语法树解析。eclipsejdt是一个开源java开发工具;其提供了丰富的应用程序编程接口(api),旨在实现代码解析的任务。利用eclipsejdt中的众多api可以顺利完成代码信息提取工作。

首先,java方法本身包含信息提取:为了平滑代码过滤和重构模块的过程,必须提取一些java方法本身包含信息,包括方法名,局部变量名信息,局部变量的类型信息,常量值(例如,字符串常量)和方法调用信息。通过调用eclipsejdt中的相关api对java项目作抽象语法树解析,实现上述信息的提取。

其次,java方法依赖信息提取:一个java方法缺少其对应的依赖信息时,这个java方法可能无法被理解或无意义。例如,一个java方法涉及类成员变量的使用,而明显类成员变量声明并不存在于方法体内部,仅给出一个独立存在的java方法的代码段,无法得到java方法中一些类成员变量的类型和初始值信息,从而加大了程序理解的难度。类成员变量信息属于依赖信息。由于缺少依赖信息,开发人员可能无法完全理解代码。java方法依赖信息主要包含类成员变量信息,方法调用对应的方法声明信息及限定名信息。要实现依赖信息的提取,需将java项目视为一个整体,然后调用eclipsejdt提供的api对java项目作抽象语法树解析,遍历每个java方法对应的抽象语法树,然后提取相应的依赖信息。

(3)代码过滤和重构

利用上述提取的代码信息,代码过滤和重构过程可以顺利进行。代码过滤和重构主要包含:

31)常量值替换:在java方法中许多常量值以别名的形式存在,别名的使用会导致词汇量的增加。从java方法中提取常量值信息,从而将别名还原为对应的常量值。

示例中,将常量值划分为以下类别:数字常量,字符串常量和字符常量。通过利用java项目中的java文件之间的依赖信息以及抽象语法树解析,可以提取常量值信息,并且可以平滑地推进常量值替换的工作。

32)类成员变量信息补充:由于java是一种面向对象的编程语言,因此java方法通常存在依赖信息。在这一部分,需要解决类成员变量信息的缺失问题。在给定的一个java方法中,也许会涉及到类成员变量的使用,而类成员变量声明并不存在于方法体内部,这意味着只给出一个独立存在的java方法的代码段,无法得到java方法中一些类成员变量的类型和初始值信息。故通过分析java文件来解析相关的类成员变量的声明信息,然后补充缺失的依赖信息。为了避免引入过多的冗余信息,需要只关注类型信息而不补充类成员变量声明的初始化值。为了区分当前java方法中的类成员变量声明和局部变量声明,定义模板(见表1中fieldaccess部分)来保存类成员变量信息;表1如下:

表1

33)完全限定名替换:由于java项目中java文件之间的依赖性,通常会引入完全限定名。不可能只分析当前的java类文件来实现完全限定名所指代的值。需要分析整个java项目以获取依赖性信息。值得注意的是,仅当相应的完全限定名是常量值(例如,字符串常量)时才进行替换。

34)方法调用重构:在抽象语法树中,一个方法调用节点可以表示为如下形式:

[expression.]identifier([expression{,expression}])}

为了便于理解上述形式,对其进行了如下形式的简化:

[varname/qualifiedclass.]

identifier

([paramname{,paramname}])}

上述形式中的第一行可能不存在,其为变量名或者为完全限定类名。第二行指的是java方法名。第三行是指参数名称列表。基于上述形式,设置两个模板来重建方法调用。如果出现不存在varname部分的方法调用,将方法调用与如下形式的模板相匹配:

qualifiedclass.identifier

(paramtype{,paramtype}])([paramname{,paramname}])

否则,将方法调用与第二个模板进行匹配,模板形式如下:

(qualifiedclass)varname.identifier

(paramtype{,paramtype}])([paramname{,paramname}])。

35)trycatch过滤:java方法中的try语句可以帮助捕获异常而不需要使用关键字throw来退出当前java方法。异常处理程序出现在try语句之后,并由关键字catch来进行标识。考虑到catch子句与代码注释无关,故只关注try语句的主体,忽略catch子句。由此,可以减少代码序列的长度,压缩词汇量的大小并削减冗余信息,以便构建高质量的数据集。

36)循环和条件语句重构:一些循环和条件语句在java方法中起着至关重要的作用。为了强调这些语句的重要性,通过表1中的模板选择和重构if语句和for语句。其中,if语句设置为与ifstatement对应的模板匹配,而包含两个样式的for语句设置为分别与forstatement和enhancedforstatement对应的模板匹配。

为了解释循环和条件语句重构方法,表2中呈现了for语句的一种重构算法,其他循环和条件语句的重构算法是相似的。表2如下:

表2

37)标识符替换:引入一种标识符替换机制,压缩代码的词汇量。具体来说,用一些特定的标记替换java方法中的标识符。首先,按出现频率对java方法中所有标识符进行排序,并选择前30,000个出现频度最高的标识符作为代码词汇表。然后,对于超出代码词汇表中的那些标识符,进行相应的替换操作。至于替换操作,可以分为六个类别,包括方法名替换,方法调用替换,常量值替换,变量类型替换,变量名替换和方法声明替换。相应地,引入一些特殊的标记作为替换标记,参见表2。考虑到java方法只存在一个方法名,只添加一个固定标记<methodname>作为方法名的替换标记。认为区分字符串常量值是没有意义的,因此,用固定标记stringliteral作为字符串常量值的替换标记。类似地,用标记<characterliteral>替换字符常量。至于其他特殊标记,都包含一个变量i,一个非负整数,旨在相互区分。在进行标识符替换操作之后,超出代码词汇表中的标识符将被上述标记替换。在构建的数据集中,代码的最终词汇量大小为30,351。表3如下:

表3

38)方法条目过滤:考虑到构造函数,其目的是为某个类创建一个实例对象。开发人员阅读和理解这些java方法非常简单和容易,因此,无需将这些java方法作为数据集的一部分。因此,从数据集中删除所有构造函数。同样,也消除了getter方法,setter方法和test方法。此外,java方法的代码序列的长度限制在10到400之间。代码序列长度小于10的java方法过于简单,而代码序列长度超过400的java方法过于复杂,其都不适合在数据集中存在,故从数据集中被滤除。

(4)javadoc过滤

为了获得<代码,注释>对,javadoc过滤也起着重要作用。数据集源于github的众多java项目。不难想象java方法的javadoc的质量是不均衡的。考虑到神经网络模型是由数据驱动的,必须为javadoc进行过滤操作,并最终构建一个干净清晰的数据集。

javadoc的第一句通常表达整个java方法的含义。因此,选择将javadoc的第一句作为java方法的注释。对于没有javadoc的方法,不会将其作为数据集的一部分。只单纯地把javadoc中的第一句话作为java方法的注释是远远不够的,还需在此基础上对获取的注释执行过滤操作。

41)通过设定模板对注释进行过滤:部分java方法虽然注释存在,但是其对应的注释不能提供任何有效信息来帮助程序理解。首先,很多注释表明当前的java方法是用于测试、调试或者未实现的。其次,一些java方法的注释是由一些工具自动生成的。除此之外,许多注释都包含警告信息,以告知不要使用这些注释或java方法。面对这些情况,定义了用于注释过滤的模板,见表4,旨在提高最终获得的代码注释的质量。

表4

42)利用词性标注技术过滤注释:为了进一步提高数据集的质量,采用词性标注(pos)技术对注释进一步过滤。如果一条注释中不包含动词,那么这条注释不足以作为java方法的功能说明表述,这样的java方法最终需从数据集中被滤除。为了利用词性标注信息,选择stanfordtagger工具,其为最常用的英语词性标注工具。同时,设置两个阈值,使注释的长度限定在有限的范围内,分别设定3为最小长度和30为最大长度。不在长度范围要求内的注释将会被从数据集中滤除。

43)标识符替换:通过观察java方法的注释,发现代码中的许多标识符同样会出现在相应的注释中。考虑到代码和注释之间的关联关系,进行标识符的替换操作。对于注释,按出现频率对所有唯一标识符进行排序,并选择前30,000个标识符作为注释的词汇表。然后,对于注释词汇表中的标识符,进行四种替换操作,方法名替换,方法调用替换,变量类型替换和变量名称替换。注释中替换的标识符与代码中替换的标识符相匹配。例如,如果代码和注释中出现的一个标识符不在两个词汇表中并被替换为<simplename_1>,则注释中的标识符同样将被替换为<simplename_1>。在这种情况下,即使用特殊标记来替换一个标识符,也可以通过记录和利用提取的信息将特殊标记转换为其原始形式。本发明的方法不仅可以减少注释词汇表的大小,还可以存储并恢复特殊标记的原始形式。

在完成上述所有过滤操作后,无法确保剩余的注释完全准确,没有噪音。示例中仅为构建一个高质量的数据集。

(5)代码注释生成模型训练

通过应用编码-解码模型来训练示例中的代码注释生成模型。编码-解码模型已被广泛用于神经网络机器翻译任务。编码-解码模型包含两部分:一个部分为编码器,用于将输入序列映射到一个固定维度的向量;另一部分解码器,用于对固定维度的向量进行解码,以输出目标序列。

在本示例中,选择长短期记忆网络(lstm)作为编码-解码模型的基本神经元。

将<代码,注释>对作为模型训练的输入,以此来训练代码注释生成模型。

将训练序列中的特殊标记<sos>和<eos>分别添加为开始标志和结束标志。代码的最终词汇表大小30351。该模型通过利用tensorflow框架扩展编码器-解码器模型,并以python语言实现。超参数是根据模型在验证集上的性能确定的。使用随机梯度下降(sgd)来训练和更新参数。minibatch大小设置为100,lstm隐藏状态和词嵌入的维度设置为512。学习率首先设置为0.99,影响因子设为0.8。参数梯度的上限为5。为避免过拟合现象的发生,设置dropout为0.3。

在gpu上训练模型。训练大约有70个步长。在验证集上计算bleu分数以选择最佳模型。在解码过程中,将集束搜索的值设置为5,注释的最大生成长度为30。

综上所述,本发明利用程序静态分析、神经网络以及自然语言处理等技术,为java方法自动生成注释。

使用两种自动机器翻译度量标准bleu-4和meteor来评估代码注释生成模型的性能。bleu-4已被广泛用于多机器翻译任务中的准确度测量。meteor是一种面向召回的指标。这两个指标还用于其它一些代码注释生成任务,以测量准确性。

参照表5,其为本发明的性能验证的数据集,统计结果如下:

表5

参照表6,其为本发明用于代码注释生成模型训练的数据集,统计结果如下:

表6

参照表7,其为本发明在bleu-4和meteor两个度量指标上的性能,统计结果如下:

表7

代码注释生成模型命名为contextcc,从表7中可以看到,本发明所提出的方法相较于最基本的编码-解码模型方法,即encoder-decoder,在bleu-4和meteor两个度量指标上均表现出更好的性能。其中,bleu-4的值达到了42.01%,在性能上相较于最基本的编码-解码模型方法提升了将近10个百分点,整体上提高了30.30%。meteor的值达到了29.26%,相较于最基本的编码-解码模型方法提升了大约7个百分点,整体上提高了30.98%。

本发明具体应用途径很多,以上所述仅是本发明的优选实施方式,应当指出,对于本技术领域的普通技术人员来说,在不脱离本发明原理的前提下,还可以做出若干改进,这些改进也应视为本发明的保护范围。

当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1