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.
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.
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:
main() were listed in 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
has listed below it a line like:
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"
Function2() also lists a line below it that is
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()
Function3()MAY throw an exception of type int
as a result of a call to
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.
EDoc application command line argument:
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
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
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 "
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
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
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
are only showing the documentation for
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
Firstly notice that from calling
different types of exceptions may result:
You will notice that it contains a single Originating from
block. This says that the exception of type "
is originally thrown from a single place:
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
Underneath the Originating from block there are two lines:
P: Function1() E: Function2()
These lines tell us how the given exception
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
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
The E line tells us that exception type
Exception" originating from
can also enter
Function3() by a definite function call
In our code we see that
Function2() which calls
thus we get this exception.
Much is similar to exception type "
except there are two main differences.
FileException originating from
Function2() has a "Rethrown" line. This indicates that
Function3() by a
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
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: "
Function1() and the other in
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().
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.
A must-not-throw block of code may propagate an exception.
Exception may propagate through restrictive specifier.
Rethrow may occur outside catch block.
An exception may propagate out to a static initialiser.
Failed to merge dictionaries
An exception may propagate out the main function.
An exception may propagate through a function that was compiled with the -fno-exceptions flag.
Function has differing throw specifiers.
Two functions with vague linkage have differing implementations.
Catch block never entered.
The std::set_unexpected function is being used but is not yet supported by EDoc++
Function used but no implementation found
Function has multiple implementations
Invalid optional input file
An exception may propogate through a destructor