有没有办法在Delphi中找到未使用的事件处理程序?

有没有办法在Delphi中找到未使用的事件处理程序?,delphi,event-handling,vcl,dead-code,Delphi,Event Handling,Vcl,Dead Code,在Delphi中查找死代码通常非常简单:只需编译并扫描缺少蓝点的例程。聪明的链接器在大多数情况下都能很好地跟踪他们 问题是,这对事件处理程序不起作用,因为它们是已发布的方法(理论上)可以通过RTTI以某种方式调用,即使在实际操作中几乎从未发生过这种情况 我正试图清理一个巨大的VCL表格单元,它在历史上被多次弯曲、折叠、旋转和破坏。如果我有办法找到表单的DFM实际上没有引用的事件处理程序并将其删除,那就太好了。有什么简单的方法可以做到这一点吗?例如,插件式IDE专家?没有解决方案可以保证在最一般的

在Delphi中查找死代码通常非常简单:只需编译并扫描缺少蓝点的例程。聪明的链接器在大多数情况下都能很好地跟踪他们

问题是,这对事件处理程序不起作用,因为它们是已发布的方法(理论上)可以通过RTTI以某种方式调用,即使在实际操作中几乎从未发生过这种情况


我正试图清理一个巨大的VCL表格单元,它在历史上被多次弯曲、折叠、旋转和破坏。如果我有办法找到表单的DFM实际上没有引用的事件处理程序并将其删除,那就太好了。有什么简单的方法可以做到这一点吗?例如,插件式IDE专家?

没有解决方案可以保证在最一般的情况下给出正确的答案(正如您所注意的,基于通过RTTI调用他们的可能性)

一种解决方案是进行代码覆盖率测试,并仔细查看从未访问过的处理程序。

这有点难看(好吧,它非常难看),但对于一个单元来说,它几乎是万无一失的,并且不需要额外的工具:

  • 确保表单的当前版本已签入源代码管理
  • 转到事件处理程序所在类的接口顶部。删除所有事件处理程序方法接口
  • 查看代码管理器/错误洞察。将突出显示具有实现但没有接口的方法。删除实现
  • 现在保存该单元。Delphi将一次一个地抱怨实际处理的每个事件缺少事件处理程序。当出现错误时,把这些写下来
  • 签出表单的原始版本,并删除列表中没有的事件处理程序

  • 我不知道有没有现成的应用程序或插件可以做到这一点,但编写脚本应该不难

    假设您没有使用RTTI或手动分配事件处理程序:(我是C++Builder用户,而不是Delphi用户,因此以下内容可能不太正确。)

  • 列出代码中所有已发布的方法。
    • 正确的方法是读取
      *.pas
      。查找以
      声明或
      发布的
      指令开头,以
      结束
      私有
      公共
      结尾的每个文本块。在每个文本块中,提取每个
      过程
    • 实现这一点的简单方法是列出常见事件处理程序类型,并假设它们已发布
  • 一旦您有了这个列表,打印列表中所有在DFM文件中找不到的内容
  • 我最喜欢使用Cygwin或Linux工具编写脚本。下面是一个在Cygwin中工作的bash脚本,它应该可以执行您想要的操作

    #!/bin/bash
    
    for file in `find -name *.pas`; do
        echo $file:
    
        # Get a list of common event handling procedures.
        # Add more types between the | symbols.
        egrep '^[[:space:]]+procedure.*(Click|FormCreate|FormClose|Change|Execute)\(' $file | 
        awk '{print $2}' | cut -f 1 -d '(' > published.txt
    
        # Get a list of used event procedures.
        egrep '^[[:space:]]+On.* =' ${file%.pas}.dfm | awk '{print $3}' > used.txt
    
        # Compare the two.
        # Files listed in the left column are published but not used, so you can delete them.
        # Files in the right column were not by our crude search for published event 
        # handlers, so you can update the first egrep command to find them.
        comm -3 published.txt used.txt
    
        echo
    
    done
    
    # Clean up.
    rm published.txt used.txt
    
    如果您不熟悉Cygwin,要实际使用此功能:

    • 下载并安装Cygwin。我认为默认安装应该提供我使用的所有工具,但我不确定
    • 将脚本保存到源目录中,作为
      cleanup.sh
    • 启动Cygwin命令提示符
    • 如果您的源代码位于c:\MyApp中,请键入
      cd/cygdrive/c/MyApp
    • 键入
      /cleanup.sh
      ,然后按Enter键

    从自动的角度来看,我认为这是不可能的。事件处理程序在对象内部发生特定事件时激活。在给定的运行中没有触发偶数并不意味着没有执行路径来引导偶数

    此外,您还可以在运行时动态分配处理程序,这样在一种情况下使用的处理程序就不会受到限制

    e、 g

    button.onclick:=DefaultClickHandler

    button.onClick:=SpecialClickHandler

    假设click处理程序与onclick事件签名匹配,但如果签名不正确,则无法获得编译


    但是,通过查找所有具有(Sender:TObject)方法签名的方法并将其与.dfm中的方法进行比较,您可能会找到所有被放弃的处理程序(如果您使用的是旧版本的delphi,请确保将其保存为文本),在我的书中,没有自动连接的东西是可疑的

    --


    如果不想沿着cygwin的路径走,可以将src和dfm加载到两个TStirngLists中,从每个TStirngLists中删除名称/标识,并生成一个包含两个循环和一些字符串操作的列表。我猜大概要花20分钟的时间才能得到你能接受的东西。

    有一种方法比克雷格的简单得多

    转到可疑事件处理程序。以一致的方式重命名它——我通过在名称前面放一个x来完成这一操作,然后转到实现并执行相同的操作。看看编译器是怎么想的

    如果它不高兴,你就把名字改回去

    您可以使用相同的方法来消除不再执行任何操作的数据元素。

    使用“重命名方法”重构来重命名每个事件处理程序。选中“重构前查看引用”复选框

    检查重构窗口。如果事件处理程序链接到控件,则会有一个“VCL设计器更新”部分显示哪些控件链接到该方法

    这还将显示该方法是从任何其他单元调用的,还是以编程方式分配的


    注意:这是针对D2006的,在以后的版本中可能略有不同。

    包含所谓的。它还显示未连接到任何组件的事件处理程序。

    我不是在寻找“最一般的情况”;我在寻找最常见的情况:对照DFM中引用的处理程序,检查PAS文件表单声明顶部声明的事件处理程序列表,并报告任何孤立事件。谢谢,但正如我对MarkusQ所说的,我在这里看到的是最常见的情况,而不是例外情况。我很清楚,有