Page 18 - 《软件学报》2026年第7期
P. 18
赵英全 等: 基于大语言模型的 Java 新特性测试程序生成 2703
用的局部变量. TraverseAST 首先将插入点 I 标记为终止节点 stop (第 8 行). 随后, 从 stop 节点开始采用倒序遍历
的方式, 识别 stop 节点的父节点 father (第 10 行). 通过对 father 节点的所有子节点进行遍历, 如果在遍历过程中匹
配到终止节点 stop, 则会终止对当前子树的遍历 (第 12–14 行); 如果在遍历的过程中识别到变量定义, 则会将该节
点所对应的变量名称及类型保存至集合 R 中 (第 15–19 行). 当 father 节点的所有子节点都遍历完成之后, stop 节
点将被更新为当前的 father 节点 (第 21 行). 并将继续向上遍历其父节点的子节点, 直至遍历至当前方法 AST 的
root 节点为止 (第 22 行). 最终, TraverseAST 将会返回识别到的可复用程序元素集合 R (第 23 行), 用于为代码片段
的生成提供上下文信息.
算法 1. 可复用程序元素识别.
输入: 种子程序 S; 被选中的插入点 I; 插入点所在方法的抽象语法树 T;
输出: 可复用的程序元素集合 R.
1. Function IdentifyReuseableElements (S, T, I)
2. R ← []; /*记录可复用程序元素*/
R ← R∪GetReuseableGlobalFields(S ); /*识别可复用全局变量*/
3.
4. R ← R∪GetReuseableFunctions(S ); /*识别可复用函数定义*/
R ← TraverseAST (T.root,I,R); /*识别可复用局部变量*/
5.
6. return R;
7. Function TraverseAST(T.root,I,R)
8. stop = I;
9. do
10. father = stop.father;
11. for each child in father.children do
12. if child == stop then
13. break; /*匹配到终止节点, 终止当前子树遍历*/
14. end
15. if child is a variable declaration then
16. varName ← child.name;
17. varType ← child.type;
18. R ← R∪{(varName,varType)}; /*记录变量名称及其类型*/
19. end
20. end
21. stop = father;
22. while stop != T.root /*遍历直至根节点*/
23. return R;
为了进一步说明可复用程序元素的提取过程, 图 6 展示了图 1 中种子程序 (不包含浅蓝色生成代码部分) 可
复用元素的提取过程. 为了方便说明, 图 6 中对方法 AST 中的部分节点进行了省略和合并, 以减少庞大的节点数
量. 在该示例中, 每个 AST 节点对应种子程序中的一个组成部分. 其中, 标记为 VarDel 的节点表示变量定义, 例如
节点 2、3 对应图 1 中种子程序的第 3 行. 需要注意的是, 标记为 Expr 的节点为表达式节点, 例如, 节点 8, 该节点
的后继节点为对象 o 创建的一个新的引用 (对应图 1 中的第 5 行). 该节点未声明新的变量定义, 因此节点 8 未被
标记为 VarDel 节点.
为了提取可复用的程序元素, LumiX 首先在 AST 中随机选择一个节点作为新生成代码的插入点, 即新生成的

