Page 133 - 《软件学报》2025年第7期
P. 133

3054                                                       软件学报  2025  年第  36  卷第  7  期


                 记录相应的终点      target (第  4–5  行). 由于调用边  edge 的类型对应于从  source 到  target 的具体场景, 算法将  edge 的
                 类型  edge.type 添加至  target 对应的预期使用场景    expectedScenesMap[target] (第  6  行). 然后, 算法对依赖树  DT  中
                 深度为   1  的依赖库  (即直接依赖库)dep     进行遍历, 并提取模块中声明的          dep  的实际依赖范围     declaredScope (第
                 8–9  行). 随后, 利用  getCorrespondingScenes 函数获取依赖范围  declaredScope 对应的使用场景   actualScenes (第
                 10  行), 并从  expectedScenesMap  中取出预期依赖范围  expectedScenes (第  11  行). 通过比较依赖范围对应的使用场
                 景  actualScenes 与预期使用场景  expectedScenes, 若存在不一致情况, 则将依赖库      dep 加入集合  JS 中 (第  12–13 行).

                 算法  1. 依赖范围误用检测.

                 输入: DT: 依赖树; CG: 调用图;
                 输出: JS: 出现依赖范围误用的依赖库集合.

                 1.   JS ⇐ {};
                 2.   expectedScenesMap ⇐ {};
                 3.   source ⇐ CG.source;
                 4.   for edge ∈ CG and edge.from = source do
                 5.    target ⇐ edge.to;
                 6.    expectedScenesMap[target].add(edge.type);
                 7.   end for
                 8.   for dep ∈ DT and dep.depth = 1 do
                 9.    declaredScope ⇐ dep.scope;
                 10.  actualScenes ⇐ getCorrespondingScenes(declaredScope);
                 11.  expectedScenes ⇐ expectedScensMap[target];
                 12.  if expectedScenes != null and actualScenes != expectedScenesMap then
                 13.   JS.add(dep);
                 14.  end if
                 15. end for
                    总的来说, 此算法通过分析调用图中不同类型的调用边来确定依赖库的预期使用场景, 并将其与依赖库的实
                 际依赖范围对应的使用场景进行比较, 输出所有不一致的依赖库. 以图                         6  为例, Maven  项目中使用了依赖库
                 org.projectlombok:lombok, 并将其依赖范围设置为   compile. 依赖库  lombok [44] 是一个能够通过在源代码中简单注解
                 自动生成样板代码的依赖库. 由于它在构建时生成代码, 而不会出现在字节码中, 因此其依赖范围应该设置为
                 provided, 然而实际上却设置为     compile, 这就引发了依赖范围误用. 根据我们的检测算法, 由于             lombok  的类不会出
                 现在字节码中, 因此调用图中不会存在指向              lombok  的运行调用边. 因此, 预期使用场景不包括运行时. 然而, 实际
                 依赖范围为    compile 的使用场景却包括了运行时, 这就导致了不一致. 因此, 检测算法会将                   lombok  标记为出现依
                 赖范围误用的依赖库, 从而成功进行检测.

                                            依赖于        相关配置    <dependency>
                                                                  <groupId>org.projectlombok</groupId>
                                                                  <artifactId>lombok</artifactId>
                                       模块 mod   依赖库 lombok        <version>1.18.12</version>
                                                                  <scope>compile</scope>
                                         包含代码                  </dependency>
                                     mod.LombokUsage
                                 import lombok.ToString;
                                 @ToString
                                 public class LombokUsage {  预期范围: provided  冲突!  实际范围: compile
                                    …
                                 }
                                                图 6 出现依赖范围误用的案例
   128   129   130   131   132   133   134   135   136   137   138