Есть ли способ найти неиспользуемые обработчики событий в Delphi?

Найти мертвый код в Delphi обычно очень просто: просто скомпилируйте, а затем просканируйте подпрограммы, у которых отсутствуют синие точки. Умный компоновщик очень хорошо отслеживает их большую часть времени.

Проблема в том, что это не работает для обработчиков событий, потому что это опубликованные методы, которые (теоретически) можно каким-то образом вызывать через RTTI, хотя на практике этого почти никогда не происходит.

Я пытаюсь очистить большой блок формы VCL, который на протяжении своей истории был согнут, свернут, свернут и искалечен несколько раз. Было бы неплохо, если бы у меня был способ найти обработчики событий, на которые фактически не ссылается DFM формы, и удалить их. Есть какой-нибудь простой способ сделать это? Подключаемый модуль IDE Expert, например?


person Mason Wheeler    schedule 26.03.2009    source источник
comment
На самом деле загрузка через RTTI на практике происходит ВСЕГДА. Каждый раз, когда вы загружаете ресурс DFM, вы получаете адреса методов по имени с помощью RTTI. Вот почему обработчики событий в первую очередь опубликовали информацию о видимости. Компоновщик не интерпретирует содержимое DFM; и компилятор тоже.   -  person Rob Kennedy    schedule 27.03.2009
comment
Я все об этом знаю. Пожалуйста, не будьте педантичны. Я имел в виду ссылку через RTTI из другого места в вашем коде. (Другими словами, это делается вручную.) И это случается очень редко, если только вы не используете какую-либо технику RPC.   -  person Mason Wheeler    schedule 27.03.2009


Ответы (7)


Я не думаю, что это возможно с автоматической точки зрения. обработчики событий активируются, когда конкретное событие происходит внутри объекта. То, что даже не запускается в данном прогоне, не означает, что нет пути выполнения, который мог бы привести к нему.

также вы можете назначать обработчики динамически во время выполнения, поэтому то, что используется в одной ситуации, не гарантировано.

e.g.

button.onclick: = DefaultClickHandler;

button.onClick: = SpecialClickHandler;

Предполагается, что обработчики кликов соответствуют сигнатуре события onclick, но вы не получите компиляцию, если бы сигнатура была неверной.


однако вы, вероятно, можете найти все заброшенные обработчики, просмотрев все методы, которые имеют подпись метода (Sender: TObject), и сравнив его методы с методами в .dfm (убедитесь, что вы сохранили его как текст, если вы работа с более старой версией delphi), в моей книге под подозрением были бы не подключены автоматические соединения.

--

если вы не хотите идти по пути cygwin, вы можете загрузить src и dfm в два TStirngLists и вырвать имя / идентификаторы из каждого и сгенерировать список с парой циклов и некоторыми строковыми манипуляциями. я предполагаю, что это около 20 минут работы, чтобы получить то, с чем можно жить.

person MikeJ    schedule 26.03.2009
comment
Спасибо, но, как я сказал MarkusQ, я рассматриваю здесь наиболее частый случай, а не исключения. Я прекрасно понимаю, что не существует надежного способа найти все обработчики событий мертвого кода без ложных срабатываний в каждом случае. Это не значит, что небольшая автоматизация не может быть полезна для сужения поиска. - person Mason Wheeler; 27.03.2009

Это немного некрасиво (ладно, это много некрасиво), но для одного устройства это почти надежно и не требует дополнительных инструментов:

  1. Убедитесь, что текущая версия формы зарегистрирована в системе управления версиями!
  2. Перейдите в верхнюю часть интерфейса класса, в котором находятся обработчики событий. Удалите все интерфейсы методов обработчика событий.
  3. Посмотрите Code Explorer / Error Insight. Методы, которые имеют реализации, но не имеют интерфейсов, будут выделены. Удалите реализации.
  4. Теперь сохраните агрегат. Delphi будет по очереди жаловаться на отсутствие обработчика событий для каждого фактически обработанного события. Записывайте их по мере появления ошибок.
  5. Проверьте исходную версию формы и удалите обработчики событий для всего, чего нет в вашем списке.
person Craig Stuntz    schedule 26.03.2009
comment
Я бы добавил еще один шаг для компиляции и посмотрел, какие из них отсутствуют, потому что они вызываются через код. - person Jim McKeeth; 27.03.2009
comment
Чем это лучше, чем использовать метод рефакторинга? Он получает ссылки в коде и в dfm сразу ... - person Francesca; 27.03.2009
comment
Я считаю, что удалить проще, чем рефакторинг, но, полагаю, это вопрос личного выбора. - person Craig Stuntz; 28.03.2009

Используйте рефакторинг «Rename Method», чтобы переименовать каждый обработчик событий. Установите флажок «Просмотреть ссылки перед рефакторингом».

Проверьте окно рефакторинга. Если обработчик событий связан с элементом управления, появится раздел «Обновления конструктора VCL», в котором будет показано, какие элементы управления связаны с методом.

Это также покажет, вызывается ли метод из каких-либо других модулей или назначается программно.

Примечание: это для D2006, может немного отличаться в более поздних версиях.

person Gerry Coll    schedule 26.03.2009

обозреватель кода ModelMaker содержит так называемый Просмотр обработчика событий. Он также показывает обработчики событий, не подключенные к какому-либо компоненту.

person Erwin    schedule 13.09.2011
comment
Обозреватель кода ModelMaker теперь бесплатен и находится на странице mmx-delphi.de. В представлении обработчика событий можно можно посмотреть в коротком видео на странице mmx-delphi.de/demo-movies - person Otherside; 08.11.2018
comment
Это действительно отличное решение. Как отмечалось выше, MMX является бесплатным и имеет ряд замечательных функций. Я использую инструмент сортировки кода, средство форматирования uses, а представление обработчика событий отлично подходит для поиска неиспользуемых событий. - person MarkF; 10.02.2020

Не существует решения, которое гарантированно дало бы правильный ответ в самом общем случае (основанном, как вы заметили, на возможности вызова их через RTTI).

Одним из решений было бы провести тесты покрытия кода и внимательно посмотреть на обработчики, которые никогда не были достигнуты.

person MarkusQ    schedule 26.03.2009
comment
Я не ищу самый общий случай; Я ищу наиболее распространенный случай: сравните список обработчиков событий, объявленных в верхней части объявления формы в файле PAS, с обработчиками, на которые есть ссылки в DFM, и сообщите о любых сиротах. - person Mason Wheeler; 27.03.2009

Мне не известно о существовавшем ранее приложении или плагине для этого, но создать сценарий не составит труда.

Предполагая, что вы не используете RTTI или не назначаете обработчики событий вручную: (Я использую C ++ Builder, а не Delphi, поэтому следующее может быть не совсем правильным.)

  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.
    • Самый простой способ сделать это - составить список распространенных типов обработчиков событий и предположить, что они опубликованы.
  2. Получив этот список, распечатайте из него все, чего нет в вашем файле DFM.

Мне удобнее всего использовать инструменты Cygwin или Linux для написания сценариев. Вот сценарий bash, который работает в Cygwin и должен делать то, что вы хотите.

#!/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.
person Josh Kelley    schedule 26.03.2009
comment
+1 за правильный способ справиться с этим: я напишу короткий сценарий, который может это сделать. Однако описанный способ поиска обработчиков событий с помощью egrep плох. Я предполагаю, что awk должен быть лучше подготовлен для этого, и использование python для всего было бы гораздо лучше. - person mghie; 27.03.2009
comment
Использование параметра компилятора --doc и запуск полученного XML-файла также должно помочь получить список опубликованных методов формы. - person mghie; 27.03.2009
comment
Чем плох этот эгреп? (Я знаю, что это быстрый способ взлома, мне просто интересно, какие именно недостатки у него есть.) - person Josh Kelley; 27.03.2009
comment
Это не работает в контексте. Вам нужно использовать grep только между классом (TForm) и первым частным / защищенным / общедоступным. Это должно быть возможно с использованием awk, но не с использованием grep. - person mghie; 27.03.2009

Есть гораздо более простой подход, чем у Крейга.

Перейти к обработчику подозрительного события. Переименуйте его последовательным образом - я делаю это, ставя x перед именем, перехожу к реализации и делаю то же самое. Посмотрите, что об этом думает компилятор.

Если это не нравится, просто измените имена обратно.

Вы можете использовать тот же подход для удаления элементов данных, которые больше ничего не делают.

person Loren Pechtel    schedule 26.03.2009