Как узнать, какие исключения может выполнять функция Delphi?

Есть ли хороший способ узнать, какие исключения может вызвать процедура/функция в Delphi (включая его называемые процедурами/функциями)?

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

Существуют ли инструменты анализа кода, которые обнаруживают необработанные исключения?

Ответ 1

(Edit: теперь очевидно, что вопрос касается только проверки времени разработки).

Новый ответ:

Я не могу указать, есть ли какие-либо инструменты для проверки этого. Анализатор Pascal, например, не работает.

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

Почему? Поскольку основной цикл сообщения в TApplication.Run() обертывает все вызовы HandleMessage() в блоке обработки исключений, который захватывает все типы исключений. Таким образом, вы будете иметь неявное/дефолтное исключение обработки около 99,999% кода в большинстве приложений. И в большинстве приложений эта обработка исключений будет составлять около 100% вашего собственного кода - 0,001% кода, который не обернут обработкой исключений, будет автоматически сгенерированным кодом.

Если у вас есть инструмент для проверки этого, вам нужно будет переписать Application.run() таким образом, чтобы он не включал обработку исключений.

(Предыдущий ответ: Обработчик события Application.OnException может быть назначен для обнаружения всех исключений, которые не обрабатываются другими обработчиками исключений. Хотя это время выполнения и, возможно, не совсем то, что вам нужно (похоже, вы хотите идентифицировать их во время разработки), это позволяет вам замаскировать любое исключение, которое не обрабатывается в другом месте. В сочетании с такими инструментами, как материал JCLDebug в Jedi Code Library, вы можете записать трассировку стека, чтобы узнать, где и почему произошло исключение, что позволило бы провести дальнейшее расследование и добавить обработку или предотвращение исключительных ситуаций вокруг виноватого кода...)

Ответ 2

Я предполагаю, что вы пытаетесь заставить Delphi вести себя как Java, что не является хорошим подходом. Я бы посоветовал не слишком беспокоиться о необработанных исключениях. В худшем случае они перейдут на общий обработчик исключений VCL и вызовутся диалоговое окно с сообщением Windows. В обычном приложении они не остановят приложение.

Хорошо написанный код будет документировать различные исключения, которые могут быть подняты, чтобы вы могли обработать их значимым образом. Обработчики Catch-all не рекомендуются, так как нет никакого способа узнать, что делать, если вы не знаете, почему было создано исключение. Я также могу рекомендовать madExcept.

Ответ 3

За исключением проверки ключевого слова "raise", в Delphi нет языковой конструкции, которая сообщает случайному читателю, какие исключения можно ожидать от метода.

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

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

Существуют несколько библиотек, которые могут помочь вам в анализе исключений во время выполнения, таких как madExcept, JclDebug и EurekaLog. Эти инструменты могут регистрировать все виды информации об исключении, поэтому очень полезно использовать один из них!

Ответ 4

Любое исключение, не явно или обычно обрабатываемое на определенном уровне, будет стекать вверх в стеке вызовов. Delphi RTL (библиотека времени выполнения) будет генерировать набор различных классов исключений - (математические ошибки, ошибки доступа, ошибки, связанные с классом и т.д.). Вы можете использовать их специально или вообще в разных попытках, кроме блоков.

Вам не нужно объявлять какие-либо новые классы исключений, если вам не нужно распространять определенный функциональный контекст с исключением.

Как писали предыдущие комментаторы, вы также можете добавить мать всех обработчиков исключений, таких как MadExcept или EurekaLog, чтобы поймать неотображаемые.

edit: Это защитная оболочка от необработанных исключений.

try
  ThisFunctionMayFail;
except
  // but it sure won't crash the application
  on e:exception
  do begin
    // something sensible to handle the error 
    // or perhaps log and/or display the the generic e.description message
  end
end;

Ответ 5

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

Одна из основных особенностей Delphi заключается в том, что исключения являются иерархическими: все определенные исключения языка относятся к Exception, хотя стоит отметить, что на самом деле возможно поднять любого потомка TObject.

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

// Other code . . . 
try
  SomeProcedure()
except  // BAD IDEA!
  ShowMessage('I caught them all!');
end;

Это поймает все, даже экземпляры повышенного TObject. Хотя я бы сказал, что это редко лучший способ действий. Обычно вы хотите использовать блок try/finally, а затем разрешить глобальный обработчик исключений (или один последний блок try/except) для обработки исключений.

Ответ 7

Я второй (или третий) MadExcept. Я успешно использовал его в нескольких коммерческих приложениях без каких-либо проблем. Хорошая вещь о MadExcept заключается в том, что она создаст отчет для вас с полной трассировкой стека, которая, как правило, укажет вам в правильном направлении относительно того, что пошло не так, и может даже включить скриншот, а также автоматически отправил вам письмо по электронной почте с компьютера клиента с простым щелчком мыши.

Однако вы не хотите использовать это для ВСЕХ исключений, просто чтобы поймать те, которые вы пропустили. Например, если вы откроете базу данных и логин завершится неудачно, вам будет лучше поймать и обработать эту проблему самостоятельно, вместо того чтобы дать пользователю ошибку по умолчанию MadExcept в сообщении вашего приложения.

Ответ 8

Для выполнения времени выполнения Eurekalog. Я не знаю, существует ли инструмент для времени разработки. У вас будет больше dificoulties, даже если у вас есть сторонний код без источника. В Delphi нет необходимости ловить исключения, поэтому вам не нужно объявлять их, как в Java.

Я хотел сказать, что Delphi не требует обработки исключения. Это просто прекратит программу. EurekaLog предоставляет средства для регистрации обработанных и необработанных исключений и предоставления большого количества информации о состоянии программы при возникновении исключения, включая строку кода, в которой он находился, и стек вызовов в то время.

Ответ 9

Как указывает Джим МакКит, вы не можете получить окончательный ответ, но мне кажется, что можно частично ответить на вопрос каким-то статическим анализом: с учетом конкретной функции/процедуры постройте граф вызовов. Проверьте каждую из функций в этом графике вызовов для оператора raise. Это скажет вам, например, что TIdTcpClient.ReadString может поднять EIdNotConnected (среди прочих).

Умный анализатор может также заметить, что некоторый код использует оператор/и включает EDivByZero как возможность, или что какая-то процедура обращается к массиву и включает ERangeError.

Это ответ немного сложнее, чем просто grepping для "рейза".

Ответ 10

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

Я думаю, что в среде Delphi IDE есть встроенная "трассировка стека" или "дерево стека" что-то вроде.

Этот вопрос напоминает мне игру SkyBuck TRussianRoulette... google it, это код и ответ могут помочь.