Page 191 - 《软件学报》2026年第5期
P. 191
2070 软件学报 2026 年第 37 卷第 5 期
$1;1712916717267212400;public boolean org.argouml.cognitive.AndCM.isRelevant(org.argouml.cognitive.Critic,
org.argouml.cognitive.Designer);<no-session-id>;3821726496288932241;1712916717267193700;1712916717267212300;DESKTOP-
0JCC7QM;973;2
$1;1712916717267213100;public void org.argouml.cognitive.Critic.beActive();<no-session-
id>;3821726496288932241;1712916717267212800;1712916717267213000;DESKTOP-0JCC7QM;993;2
$1;1712916717267214300;protected java.util.List org.argouml.cognitive.CompositeCM.getMechList();<no-session-
id>;3821726496288932241;1712916717267214100;1712916717267214300;DESKTOP-0JCC7QM;995;3
$1;1712916717267218700;public java.lang.String org.argouml.cognitive.Critic.getCriticName();<no-session-
id>;3821726496288932241;1712916717267216700;1712916717267218600;DESKTOP-0JCC7QM;998;5
$1;1712916717267220300;public java.lang.String org.argouml.cognitive.Critic.getCriticName();<no-session-
id>;3821726496288932241;1712916717267219800;1712916717267220200;DESKTOP-0JCC7QM;999;5
$1;1712916717267221800;public java.lang.Object org.argouml.cognitive.Critic.getControlRec(java.lang.String);<no-session-
id>;3821726496288932241;1712916717267221000;1712916717267221700;DESKTOP-0JCC7QM;1000;5
$1;1712916717267222100;public boolean org.argouml.cognitive.Critic.isEnabled();<no-session-
id>;3821726496288932241;1712916717267216200;1712916717267222100;DESKTOP-0JCC7QM;997;4
$1;1712916717267222500;public boolean org.argouml.cognitive.EnabledCM.isRelevant(org.argouml.cognitive.Critic,
org.argouml.cognitive.Designer);<no-session-id>;3821726496288932241;1712916717267215600;1712916717267222400;DESKTOP-
0JCC7QM;996;3
图 4 argoUML 软件执行后得到的部分执行轨迹
③ 分析执行轨迹, 从而获得执行过程中涉及的类
在软件执行过程中, 一个方法调用通常会引发多个后续的方法调用. 例如, 当方法 A 调用方法 B 时, 方法 B 可
能进一步调用方法 C 和方法 D. 因此, 一个方法调用往往对应着一组相关的执行记录, 这一组记录称为一个 trace.
在一个 trace 中, 所有的记录具有相同的 traceID. 此外, eoi 表示当前记录在整个 trace 中的执行顺序, 最先被执行的
方法其 eoi 值为 0; ess 表示当前方法在调用栈中的深度, 最先被执行的方法其 ess 值为 0. 因此, 通过分析一个
trace 内各记录的 traceID、eoi 和 ess, 我们可以得到该 trace 内方法之间的真实调用关系. 算法 1 描述了从执行轨
迹 (一个 trace) 提取方法之间调用关系的大致过程. 算法 1 的时间复杂度为 O(n) (n 为该 trace 内的执行记录数).
算法 1. 从执行轨迹提取方法之间的调用关系.
输入: 一个 trace (一组按照 eoi 值升序排列后的 record 记录);
输出: 方法之间的调用关系.
FOR EACH record IN trace DO
IF 栈不为空 THEN
IF record.ess≤栈顶 record.ess THEN
WHILE 栈不为空且 record.ess≤栈顶 record.ess DO //回溯
弹出栈顶 record
END WHILE
IF 栈为空 THEN
跳出 FOR 循环
END IF
PRINT “栈顶 record.methodName###record.methodName” //###: 调用
将当前 record 入栈
ELSE // 如果当前 record 的 ess 大于栈顶元素的 ess
PRINT “栈顶 record.methodName###record.methodName”
将当前 record 入栈
END IF
ELSE // 栈为空的情况
将当前 record 入栈 // 初始情况下, 将记录入栈

