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

发布于 2024-07-16 02:21:28 字数 292 浏览 8 评论 0原文

在 Delphi 中查找死代码通常非常简单:只需编译然后扫描缺少蓝点的例程即可。 大多数时候,智能链接器非常擅长追踪它们。

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

我正在尝试清理一个大型 VCL 模板单元,该单元在其历史上多次被弯曲、折叠、旋转和毁坏。 如果我有某种方法可以找到表单的 DFM 实际未引用的事件处理程序并删除它们,那就太好了。 有什么简单的方法可以做到这一点吗? 例如,插件 IDE Expert?

Finding dead code in Delphi is usually real simple: just compile and then scan for routines missing their blue dots. The smart linker's very good about tracking them down, most of the time.

Problem is, this doesn't work for event handlers because they're published methods, which (theoretically) could be invoked via RTTI somehow, even though this almost never happens in actual practice.

I'm trying to clean up a large VCL form unit that's been bent, folded, spindled and mutilated various times throughout its history. It would sure be nice if I had some way to find event handlers that aren't actually referenced by the form's DFM and delete them. Is there any easy way to do this? A plug-in IDE Expert, for example?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

何以心动 2024-07-23 02:21:28

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

  1. 确保检查表单的当前版本进入源代码管理!
  2. 转到事件处理程序所在类的界面顶部。 删除所有事件处理程序方法接口。
  3. 查看代码资源管理器/错误洞察。 有实现但没有接口的方法将突出显示。 删除实现。
  4. 现在保存该单位。 Delphi 会一次一个地抱怨实际处理的每个事件缺少事件处理程序。 当错误出现时,把这些写下来。
  5. 查看表单的原始版本,并删除列表中未列出的任何内容的事件处理程序。

This is a bit ugly (OK, it's a lot ugly), but for one unit it's close to foolproof, and requires no additional tools:

  1. Make sure that the current version of the form is checked into source control!
  2. Go to the top of the interface of the class where the event handlers are. Delete all of the event handler method interfaces.
  3. Look at Code Explorer/Error Insight. The methods which have implementations but no interfaces will be highlighted. Delete the implementations.
  4. Now save the unit. Delphi will, one at a time, complained about the missing event handler for each event that is actually handled. Write these down as the errors come up.
  5. Check out the original version of the form, and remove the event handlers for anything not on your list.
那一片橙海, 2024-07-23 02:21:28

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

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

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

注:此为D2006版本,后续版本可能略有不同。

Use the "Rename Method" refactoring to rename each event handler. Check the "View references before refactoring" checkbox.

Check the Refactoring window. If the event handler is linked to a control, there will be a "VCL Designer Updates" section show which control(s) are linked to the method.

This will also show if the method is called from any other units, or is assigned programmatically.

Note: this is for D2006, may be slightly different in later versions.

两个我 2024-07-23 02:21:28

ModelMaker Code Explorer 包含一个所谓的 事件处理程序视图。 它还显示未连接到任何组件的事件处理程序。

ModelMaker Code Explorer contains an so-called Event handler view. It also shows event handlers not connected to any component.

雨轻弹 2024-07-23 02:21:28

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

您还可以在运行时动态分配处理程序,因此在一种情况下使用的处理程序是无法保证的。

例如

button.onclick := DefaultClickHandler;

按钮.onClick := SpecialClickHandler;

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


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

--

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

I dont think this is possible from an automatic point of view. event handlers are activated when a particular event occurs inside an object. That the even is not triggered in a given run doesnt mean that there isnt an execution pathway to lead to it.

also you can assign handlers dynamically at runtime so whats used in one situation is not garuanteed.

e.g.

button.onclick := DefaultClickHandler;

button.onClick := SpecialClickHandler;

Assuming that the click handlers match the onclick event signature, but you wouldnt get a compile if the signature was incorrect.


however, you can probably find all the abandoned handlers by looking for all the methods that find have a (Sender: TObject) method signature and comparing that his of methods to those in the .dfm (make sure you save it as text if you are working with an older version of delphi), antyhing not wired up automatically would be suspect in my book.

--

if you dont want to go down the cygwin path, you can load the src and dfm into two TStirngLists and rip out the name/idents from each and generate a list with a couple of loops and some string manipulations. my guess is about 20 minutes of work to get something you can live with .

故笙诉离歌 2024-07-23 02:21:28

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

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

There is no solution that is guaranteed to give a correct answer in the most general case (based, as you note, on the possibility of calling them via RTTI).

One solution would be to do code coverage tests and look carefully at handlers that were never reached.

秋意浓 2024-07-23 02:21:28

我不知道现有的应用程序或插件可以执行此操作,但编写脚本应该不难。

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

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

I'm not aware of a preexisting app or plugin to do this, but it shouldn't be hard to script.

Assuming you're not using RTTI or manually assigning event handlers: (I'm a C++Builder user rather than Delphi, so the following may not be quite correct.)

  1. Make a list of all published methods in your code.
    • The proper way to do this is to read *.pas. Find each text block that starts with a class declaration or a published directive and ends with a end, private, or public. Within each of these text blocks, extract each procedure.
    • The easy way to do this is to make a list of common event handler types and assume they're published.
  2. Once you have this list, print everything from the list that's not found in your DFM file.

I'm most comfortable using Cygwin or Linux tools for scripting. Here's a bash script that works in Cygwin and should do what you want.

#!/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

To actually use this, if you're not familiar with Cygwin:

  • Download and install Cygwin. I think the default install should give you all of the tools I used, but I'm not positive.
  • Save the script to your source directory as cleanup.sh.
  • Start a Cygwin command prompt.
  • If your source is in c:\MyApp, then type cd /cygdrive/c/myapp
  • Type ./cleanup.sh and press Enter.
离去的眼神 2024-07-23 02:21:28

有一种比克雷格的方法更简单的方法。

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

如果不高兴你就把名字改回来。

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

There's a much easier approach than Craig's.

Go to a suspect event handler. Rename it in a consistent way--I do this by putting an x in front of the name, go down to the implementation and do the same thing. See what the compiler thinks of it.

If it's not happy you just change the names back.

You can use the same approach to eliminate data elements that no longer do anything.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文