Output Stage

The output stage is where EDoc++ generates useful information about exception propagation. The amount and style of the information generated depends on the output format chosen.

There are a number of different output formats that EDoc++ will generate. In future versions it is planned to provide a plugin interface so that users can easily write additional output format plugins.

Output formats

Currently three output formats are available. All output data be it in the doxygen, simple-doxygen or simple formats is by default sent to stdout. Instead of doing this, the user can specify the command line option "--output <filename>" in order to send the data to a file instead of stdout. One other point to note is that by default only functions that throw exceptions have output documentation generated for them. If you desire to see all functions even if they do not throw any exceptions then specify the --show-all option to edoc.

For the following sections we will continue using the src/apps/simple/ application from Example Project.

Simple Format

EDoc application command line argument: --format simple

This format is primarily used by the Unit Tests. It can be useful to give an overall view of what is happening, however the data is not well presented for users to read and it also does not give as much information as the Doxygen format.

The simple format basically works by having a new line for a new item of data. Each line starts with an identifier that indicates what type of data is on that line. The following identifiers exist:

  • F: Function with an implementation

  • V: Pure virtual function

  • U: Undefined function (No Implementation)

  • L: Functions link name (As opposed to declared name)

  • E: Propagating exception

  • O: Originating exception

  • P: Possible exception

To demonstrate we will continue using the src/apps/simple/ application from Example Project. Lets generate exception documentation for that program in the simple format.

edoc --show-all --format simple simple.edc

Will produce the following output:

edoc --disable-auto-import --show-all --format simple simple.edc
F: Function1()
O: 	Exception
O: 	FileException
O: 	int

F: Function2()
O: 	FileException
E: 	Exception  -  Function1()
E: 	FileException  -  Function1()
E: 	int  -  Function1()

F: Function3()
O: 	float
P: 	Exception  -  Function1()
P: 	FileException  -  Function1()
P: 	int  -  Function1()
E: 	FileException  -  Function2()
E: 	FileException  -  Function2()
E: 	Exception  -  Function2()
E: 	int  -  Function2()

F: main()

The first thing to notice is that our functions: Function1(), Function2(), Function3() and main() were listed in the output. The main() function does not have any exceptions listed below it which means that if called it will not throw any exceptions at all. Where you will see that Function1() has listed below it a line like:

O: int

This means that Function1() throws an exception of type int. The throw statement for it is actually part of the Function1() code and is called an "Originating" exception.

Function2() also lists a line below it that is like:

E: int  -  Function1()

This means that Function2() can throw an exception of type int. However unlike Function1() this exception does not originate from this function, but rather has entered this function due to a call it made to Function1(). This is called a "Propagating Exception" as it propogates from a different function to this one.

Function3()lists a line like:

P: int  -  Function1()

This means that Function3()MAY throw an exception of type int as a result of a call to Function1()These "Possible" Propogating exceptions occurr as a result of a function pointer call or a call to a virtual function. In such situations, it is not possible to determine exactly which function may be executed, so we list exceptions for all functions that may possibly be called as possible propogating exceptions.

Simple Doxygen Format

EDoc application command line argument: --format simple-doxygen

The Simple Doxygen format provides information in a format that can be processed directly by doxygen. This format provides a minimal amount of information that should be useful for creating API documentation. In particular for each function it will display a simple list of the types of exceptions a function may throw as a result of calling it.

Try generating simple-doxygen format data for our example:

edoc --format simple-doxygen simple.edc

Note: We removed the --show-all flag so it will omit displaying any documentation for functions that have no useful exception information. As a result edoc will display the following:

edoc --disable-auto-import --format simple-doxygen simple.edc
/*! \fn Function1()
 * \brief (BRIEF DESC NOT PROVIDED).
 *
 * \note EDoc++ data included.
 *
 * \exception Exception
 * \exception FileException
 * \exception int
 */

/*! \fn Function2()
 * \brief (BRIEF DESC NOT PROVIDED).
 *
 * \note EDoc++ data included.
 *
 * \exception Exception
 * \exception FileException
 * \exception int
 */

/*! \fn Function3()
 * \brief (BRIEF DESC NOT PROVIDED).
 *
 * \note EDoc++ data included.
 *
 * \exception Exception
 * \exception FileException
 * \exception float
 * \exception int
 */

Some import things to note. All doxygen formats currently have a "\brief (BRIEF DESC NOT PROVIDED)" and a "\note EDoc++ data included." line. These two lines do not give much in the way of exception information but are currently necessary. The first is necessary for the patched doxygen to be able to successfully accept the following documentation as documentation belonging to the functions detail section by first provided an unused brief section.

When parsing source files for documentation the modified doxygen will only keep the first brief documentation segment it encounters for a particular code element. This means that when our file is processed after all other source files. The brief statements here should be overlooked. However it is still necessary for doxygen to consider the documentation following as valid documentation for the details section. This limitation may be removed in the future.

The second item is a doxygen note section. This can be used to indicate in the documentation that a function has actually been processed using EDoc++. This is helpful in order to see any possible "Holes" in the documentation due to limitations in the interface between EDoc++ and doxygen. See the later section on Running Doxygen

Detailed Doxygen Format

EDoc application command line argument: --format doxygen

The Doxygen format provides information in a format that can be processed directly by doxygen. This format is grouped in such a way that it makes it easier for the user to read.

The Doxygen output format shows the following information:

  • Name of function

  • List of all exceptions that may result from calling the function

  • For each exception it lists the place where that exception originates from.

  • For each originating exception it lists how that exception entered this function (Originates from this function OR another function that was called from which it entered this function).

  • A list of places within this function where the exception may have been "rethrown" from.

Try generating doxygen format data for our example:

edoc --format doxygen simple.edc

We are only showing the documentation for Function3() below in order to explain its format.

EDOC -> EDOC -> $  edoc --disable-auto-import --format doxygen simple.edc
-- ONLY SHOWING FUNCTION 3 --

/*! \fn Function3()
 * \brief (BRIEF DESC NOT PROVIDED).
 *
 * \note EDoc++ data included.
 *
 * \exception Exception
 *    - Originating from: Function1()
 *       - P: Function1()
 *       - E: Function2()
 *       .
 *    .
 * <hr>
 * \exception FileException
 *    - Originating from: Function1()
 *       - P: Function1()
 *       - E: Function2()
 *         Rethrown: 1 times. Lines: ?? 
 *       .
 *    - Originating from: Function2()
 *       - E: Function2()
 *         Rethrown: 1 times. Lines: ?? 
 *       .
 *    .
 * <hr>
 * \exception float
 *    - Originating from: Function3()
 *       - O: Function3()
 *       .
 *    .
 * <hr>
 * \exception int
 *    - Originating from: Function1()
 *       - P: Function1()
 *       - E: Function2()
 *       .
 *    .
 * <hr>
 */

The documentation for Function3() covers all possible output structures for the Doxygen output. We will break this output down in order to understand exactly what it is describing.

Firstly notice that from calling Function3() four different types of exceptions may result: Exception, FileException, float and int.

Description of documentation for exception of type "Exception"

You will notice that it contains a single Originating from block. This says that the exception of type "Exception" is originally thrown from a single place: Function1() You can see that by looking at the code. I.e. There is only a single "throw Exception();" line in the code and that is in Function1().

Underneath the Originating from block there are two lines:

P: Function1()
E: Function2()

These lines tell us how the given exception enters Function3(). The letter at the start of the line indicates one of:

  • O : Originates from function

  • E : Propagates from calling function

  • P : POSSIBLY propagates from calling function

The P line tells us that exception type "Exception" originating from Function1() can enter Function3() by a POSSIBLE function call to Function1(). Looking at the code this is what happens. Function3() calls a function pointer which has been initialized with the address of Function1(). This is considered a possible call as it is possible that the function pointer have other values too in which case any other function whose addresses have been taken would also be used as possible function calls.

The E line tells us that exception type "Exception" originating from Function1() can also enter Function3() by a definite function call to Function2().

In our code we see that Function3() calls Function2() which calls Function1() and thus we get this exception.

Description of documentation for exception of type "FileException"

Much is similar to exception type "Exception" except there are two main differences.

The FileException originating from Function2() has a "Rethrown" line. This indicates that a FileException entered Function3() by a call to Function2() however it was caught in a catch statement somewhere in Function3() and then rethrown. This occurred once in Function3(). You can see that in the code above.

Also we see that there are two "Originating from" blocks for FileException. This means that there are two locations that a FileException may originally be thrown from. The first is in Function1() and the second is in Function2(). Again you can see that there are two lines in the code that look like: "throw FileException();" one in Function1() and the other in Function2().

Description of documentation for exception of type "float"

You can notice from the float exception that there is one little difference here. The exception of type float originates from Function3(). This shows that. The originating from block lists Function3() and the line below showing where the exception entered Function3() indicates that it "O"riginated from Function3().

Output Notifications (Errors/Warnings)

Errors and warnings are used to notify the user of a number of anomalies that may occur while processing EDoc++ data. It is helpful to note that all errors/warnings are displayed to the standard error stream and all follow a standard output format that should be easily parseable.

The error/warning format looks like:

WARNING(<warning-code>): Summary [: More details]
ERROR(<error-code>): Summary [: More details]

The errors/warnings should be looked at as they can give hints to problems that may occur due to dangerous usage of exceptions. Below is a complete list of Errors/Warnings and descriptions of what causes them.

@@@Brendon TODO Add extra documentation indicating example code or usages that may cause these to occur.

  • ENOT_THROW

    A must-not-throw block of code may propagate an exception.

  • ECRASH_SPEC

    Exception may propagate through restrictive specifier.

  • ECRASH_THROW

    Rethrow may occur outside catch block.

  • ECRASH_STATIC

    An exception may propagate out to a static initialiser.

  • EMERGE

    Failed to merge dictionaries

  • EMAIN_EXC

    An exception may propagate out the main function.

  • EUSUPP_EXC

    An exception may propagate through a function that was compiled with the -fno-exceptions flag.

  • WDIFF_THROW

    Function has differing throw specifiers.

  • WDIFF_IMPL

    Two functions with vague linkage have differing implementations.

  • WUNUSED_CATCH

    Catch block never entered.

  • WSET_UNEXPECTED

    The std::set_unexpected function is being used but is not yet supported by EDoc++

  • WDUP_TYPE

    Duplicate type

  • WDUP_FUNC

    Duplicate function

  • WUNIMPL

    Function used but no implementation found

  • WMULT_IMPL

    Function has multiple implementations

  • WINVALID_FILE

    Invalid optional input file

  • WDESTR_EXC

    An exception may propogate through a destructor