Как документировать все исключения, которые может выдать функция? - PullRequest
26 голосов
/ 25 декабря 2010

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

Примерно так (с использованием Doxygen):

/** 
 * @throw Exception ...
 * @throw ExceptionThrownByHelper ...
 * @throw ExceptionThrownByHelpersHelper ...
 */
void theFunction() 
{ 
    helperWhichMayThrowException();
}

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

Toсделать это вы можете:

  1. рекурсивно выполнять все вызовы функций theFunction() и искать исключения, возникающие в этой функции.Это большая работа, и вы можете забыть задокументировать исключение, когда добавляете исключение к помощнику.
  2. перехватывает все исключения, выданные помощниками в theFunction(), и конвертирует их, чтобы вы были уверены, что только исключенияВы указываете, брошены.Но тогда зачем использовать исключения?
  3. не беспокойтесь об исключениях, генерируемых вспомогательными функциями, но тогда вы не можете выполнить юнит-тестирование всех исключений, потому что не знаете, какие исключения могут быть сгенерированы публичной функцией
  4. какой-то инструмент, который (полу) автоматически перечисляет все исключения, выданные помощниками и т. д. Я посмотрел в документации по Doxygen, но не нашел способа сделать это.

Я хотел бы использовать вариант 4, но яеще не нашли хорошего решения, может быть, это выполнимо с Doxygen?Или, может быть, я просто хочу документально оформить ???

edit: Возможно, это не совсем понятно, но я ищу простой способ документировать все исключения (желательно с помощью Doxygen) функцииможет бросить, не проверяя вручную все вспомогательные функции.Простой способ включает «не документировать все исключения» или «перехватывать и преобразовывать все исключения в theFunction()»

Ответы [ 2 ]

14 голосов
/ 27 декабря 2010

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

Есть две части документирования сгенерированных исключений.

1) Легкий бит. Документируйте исключения, которые напрямую генерируются в вашем методе. Вы можете сделать это вручную, но это довольно трудоемко, и если вам не удается синхронизировать документы с кодом, документация вводит в заблуждение (потенциально хуже, чем отсутствие документации вообще, поскольку вы можете действительно доверять документации, в которой вы уверены на 100% точный). Моя надстройка AtomineerUtils значительно упрощает эту задачу, поскольку синхронизирует код и комментарии к документу с минимальными усилиями.

2) Немного невозможно. Документируйте все исключения, которые могут «пройти» через ваш метод. Это означает повторение через все поддерево методов, вызываемых вашим методом, чтобы посмотреть, что они могут выдать. Почему невозможно? Что ж, в простейших случаях вы будете статически привязываться к известным методам и, следовательно, можете сканировать их, чтобы увидеть, что они выдают - в меру легко. Но в большинстве случаев в конечном итоге вызываются динамически связанные методы (например, виртуальные методы, отраженные или COM-интерфейсы, методы внешних библиотек в dll, API-интерфейсы операционной системы и т. Д.), Для которых вы не можете окончательно определить, что может быть выброшено (как вы не будете знать, что называется до тех пор, пока вы на самом деле не запустите программу на ПК конечного пользователя - все ПК отличаются друг от друга, и код, выполняемый на (например) WinXP и Win7, может сильно отличаться. Или представьте, что вы вызываете виртуальный метод, а затем кто-то добавляет плагин -в вашей программе, которая переопределяет метод и генерирует исключение нового типа). Единственный способ надежно справиться с этой ситуацией - перехватить все исключения в вашем методе, а затем повторно выдать конкретные, которые затем можно точно задокументировать - если вы не можете сделать это, то документирование исключений в значительной степени ограничено Бросали и обычно ожидали исключения "в вашем методе", оставляя "исключительные ошибки" в основном недокументированными и просто передавались на более высокий уровень блоков обработки необработанных исключений (Именно это ужасное «неопределенное» поведение исключений часто приводит к необходимости использования catch (...) - академически это «зло», но если вы хотите, чтобы ваша программа была пуленепробиваемой, вам иногда приходится использовать catch - быть уверенным, что непредвиденные ситуации не убьют ваше приложение).

6 голосов
/ 26 июля 2012

Я придумал следующее ручное решение.По сути, я просто копирую документацию @throw от участников, которым звоню.Было бы неплохо, если бы Doxygen имел @copythrows, аналогичный @copydoc, но сработает следующее:

class A {
    public:
        /** @defgroup A_foo_throws
         *
         * @throws FooException
         */

        /** 
         * @brief Do something.
         *
         * @copydetails A_foo_throws
         */
        void foo();
};

class B {
    public:
        // This group contains all exceptions thrown by B::bar()
        // Since B::bar() calls A::foo(), we also copy the exceptions
        // thrown by A::foo().

        /** @defgroup B_bar_throws
         *
         * @copydetails A_foo_throws
         * @throws BarException
         */

        /**
         * @brief Do something else.
         *
         * @copydetails B_bar_throws
         */
        void bar();
};  

Затем в файле конфигурации Doxyfile добавьте *_throws к EXCLUDE_SYMBOLS.Это гарантирует, что эти группы не будут отображаться как модули.

Тогда B::bar() приводит к этой документации:

void B :: bar () Сделайте что-нибудь еще.

Исключения: FooException Исключения: BarException

...