【问题标题】:Java Code Use CheckerJava 代码使用检查器
【发布时间】:2010-10-20 11:18:42
【问题描述】:

我正在开发一个库,我们想确定我们的库有多少正在被使用。 IE。我们想知道我们的库中有多少方法是公开的,但从未被调用。

目标: 静态分析 确定当前项目中调用包A中每个公共方法的代码行数。如果调用次数为零,则应按此方式上报方法。

【问题讨论】:

  • 听起来您想要 Cobertura 或 Emma 之类的东西来监控您正在运行的应用程序,而不是依赖一组单元测试覆盖率?

标签: java code-coverage static-analysis


【解决方案1】:

我相信你正在寻找这个 Eclipse 插件 --> UCDetector

来自文档(注意第二个要点)

  • 不必要的(死)代码
  • 可以将可见性更改为受保护、默认或 私密
  • 字段方法,可以是最终的

在更大的范围内,如果您想进行对象级静态分析,请查看 IBM 提供的此工具 -->Structural Analysis for Java。对库、API等的对象分析非常有帮助。

【讨论】:

    【解决方案2】:

    不完全是您正在寻找的,但是:

    使用代码覆盖工具(如Cobertura)可以做类似的事情。他们不对源代码进行静态检查,而是检测字节码以在运行时收集指标。当然,您需要以一种练习所有使用模式的方式来驱动应用程序,并且可能会错过更稀有的代码路径。

    在静态分析方面,也许这些工具可以帮助您(Apache 项目使用它们来检查新版本的 API 兼容性,似乎该任务与您正在尝试做的事情有些相关):

    • Clirr 是一个检查 Java 库与旧版本的二进制和源代码兼容性的工具。基本上,你给它两组 jar 文件,Clirr 会转储出公共 api 中的更改列表。
    • JDiff 是一个 Javadoc doclet,当比较两个 API 时,它会生成所有已被删除、添加或更改的所有包、类、构造函数、方法和字段的 HTML 报告,包括它们的文档。

    【讨论】:

      【解决方案3】:

      客户端使用反射调用是静态分析中需要考虑的一个漏洞。因为没有办法确定某个特定的方法没有通过一些奇怪的反射方案被调用。因此,也许将运行时分析和静态分析结合起来可能是最好的。

      【讨论】:

        【解决方案4】:

        我认为您无法衡量需要一个类或函数的“频率”。
        有一些简单的问题:

        • 什么定义了游戏库的使用统计数据是“正常”还是“异常值”?经常在游戏中杀死自己是错误的吗?您会像一个优秀的游戏玩家一样更频繁地使用“killScreen”类。
        • 什么定义了“很多”?时间或使用次数? POJO 会消耗很少的时间,但会非常频繁地使用。

        结论:
        我不知道您要完成什么。
        如果你想显示你的代码依赖,还有其他tools 可以做到这一点。如果您尝试衡量您的代码执行情况,Java 有 profiler or benchmarks。如果您是统计极客,您会对RapidMiner 感到满意;)

        祝你好运!

        【讨论】:

          【解决方案5】:

          我建议 JDepend 向您展示包和类之间的依赖关系,非常适合查找循环依赖关系! http://clarkware.com/software/JDepend.html (它有一个 Eclipse 插件:http://andrei.gmxhome.de/jdepend4eclipse/

          还有其他指标的 PMD http://pmd.sourceforge.net/

          【讨论】:

            【解决方案6】:

            IntelliJ 有一个工具来检测方法、字段、类,这些可以有更多的限制修饰符。它还可以快速修复应用这些更改,这也可以为您节省大量工作。如果您不想为此付费,您可以获得 30 天的 eval 许可证,这足以更改您的代码,这不是您应该经常做的事情。

            顺便说一句:IntelliJ 有大约 650 次代码检查来提高代码质量,大约一半有自动修复,所以我建议花几天时间使用它来重构/整理你的代码。

            【讨论】:

              【解决方案7】:

              请查看Dead Code Detector。它声称可以满足您的需求:使用静态分析查找未使用的代码。

              【讨论】:

                【解决方案8】:

                以下是一些 Java 代码覆盖工具列表。我个人没有使用过任何这些,但它可能会让你开始:

                【讨论】:

                • 代码覆盖工具的问题在于它们在运行时工作,因此您可能会错过“罕见”的代码路径。
                【解决方案9】:

                Proguard 也可能是一种选择 (http://proguard.sourceforge.net/):

                “ProGuard 的一些用途是:

                • ...
                • 列出死代码,以便从源代码中删除。
                • ..."

                另见http://proguard.sourceforge.net/manual/examples.html#deadcode

                【讨论】:

                  【解决方案10】:

                  您可以使用 ASM 字节码分析库 (http://asm.ow2.org) 为此编写自己的实用程序(阅读本文后一小时内)。您需要实现 ClassVisitor 和 MethodVisitor。您将使用 ClassReader 解析库中的类文件。

                  • 将为每个声明的方法调用 ClassVisitor 的 visitMethod(..)。
                  • 将为每个调用的方法调用您的 MethodVisitor 的 visitMethodInsn(..)。

                  维护一个地图来进行计数。键代表方法(见下文)。这是一些代码:

                  class MyClassVisitor {
                      // ...
                      public void visit(int version, int access, String name, ...) {
                          this.className = name;
                      }
                      public MethodVisitor visitMethod(int access, String name, String desc, ...):
                          String key = className + "." + name + "#" + desc;
                          if (!map.containsKey() {
                              map.put(key, 0);
                          }
                          return new MyMethodVisitor(map);
                      }
                      // ...
                  }
                  
                  void class MyMethodVisitor {
                      // ...
                      public visitMethodInsn(int opcode, String name, String owner, String desc, ...) {
                          String key = owner + "." + name + "#" + desc;
                          if (!map.containsKey() {
                              map.put(key, 0);
                          }
                          map.put(key, map.get(key) + 1);
                      }
                      // ...
                  }
                  

                  基本上就是这样。你的节目开始时是这样的:

                  Map<String,Integer> map = new HashMap<String,Integer>();
                  for (File classFile : my library) {
                      InputStream input = new FileInputStream(classFile);
                      new ClassReader(input).accept(new MyClassVisitor(map), 0);
                      input.close();
                  }
                  for (Map.Entry<String,Integer> entry : map.entrySet()) {
                      if (entry.getValue() == 0) {
                          System.out.println("Unused method: " + entry.getKey());
                      }
                  }
                  

                  享受吧!

                  【讨论】:

                  • 如果方法 A 调用方法 B,即使方法 A 没有使用,方法 B 也会被标记为“已使用”,因此这不是正确的计数方法。您需要对“used”进行传递闭包。
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-09-24
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-04-09
                  • 2011-03-02
                  相关资源
                  最近更新 更多