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

时间:2009-03-26 21:11:55

标签: delphi event-handling vcl dead-code

在Delphi中查找死代码通常很简单:只需编译然后扫描缺少蓝点的例程。在大多数情况下,智能链接器非常适合跟踪它们。

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

我正在努力清理一个大型的VCL表格单元,它在整个历史中经过多次弯曲,折叠,旋转和切割。如果我有某种方法可以找到表单的DFM实际上没有引用的事件处理程序并删除它们,那肯定会很好。有没有简单的方法来做到这一点?插件IDE专家,例如?

7 个答案:

答案 0 :(得分:6)

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

  1. 确保将表单的当前版本签入源代码管理中!
  2. 转到事件处理程序所在类的接口顶部。删除所有事件处理程序方法接口。
  3. 查看Code Explorer / Error Insight。将突出显示具有实现但没有接口的方法。删除实现。
  4. 现在保存单位。 Delphi将一次一个地抱怨实际处理的每个事件都缺少事件处理程序。当错误出现时写下来。
  5. 查看表单的原始版本,并删除不在列表中的任何内容的事件处理程序。

答案 1 :(得分:5)

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

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

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

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

答案 2 :(得分:2)

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

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

答案 3 :(得分:2)

我不知道有一个预先存在的应用程序或插件来执行此操作,但编写脚本应该不难。

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

  1. 列出代码中所有已发布的方法。
    • 执行此操作的正确方法是阅读*.pas。查找以class声明或published指令开头且以endprivatepublic结尾的每个文本块。在每个文本块中,提取每个procedure
    • 执行此操作的简单方法是列出常见事件处理程序类型并假设它们已发布。
  2. 获得此列表后,请打印DFM文件中未找到的列表中的所有内容。
  3. 我最习惯使用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键。

答案 4 :(得分:2)

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

你也可以在运行时动态分配处理程序,这样就不会在一种情况下使用。

e.g。

button.onclick:= DefaultClickHandler;

button.onClick:= SpecialClickHandler;

假设点击处理程序与onclick事件签名匹配,但如果签名不正确,则无法进行编译。


然而,您可以通过查找找到具有(Sender:TObject)方法签名的所有方法并将其方法与.dfm中的方法进行比较来找到所有已废弃的处理程序(请确保将其保存为文本如果你正在使用旧版本的delphi),我的书中可能会怀疑没有自动连接的antyhing。

-

如果您不想沿着cygwin路径前进,可以将src和dfm加载到两个TStirngLists中,并从每个TStirngLists中删除名称/ idents,并生成一个包含几个循环和一些字符串操作的列表。我的猜测是大约20分钟的工作来获得你可以忍受的东西。

答案 5 :(得分:2)

比克雷格更容易实现。

转到可疑事件处理程序。以一致的方式重命名 - 我通过在名称前放置一个x来执行此操作,转到实现并执行相同的操作。看看编译器对它的看法。

如果不满意你只需更改名称。

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

答案 6 :(得分:2)

ModelMaker Code Explorer包含所谓的Event handler view。它还显示未连接到任何组件的事件处理程序。