Unnamed Structs/Unions
Doxygen has a major flaw in its XML model for unnamed C/C++ structs or unions. The problem is that it’s impossible to reconstruct the original declaration just from the generated XML database.
For example, the following snippet:
struct Parent
{
    int m_field1;
    struct
    {
        int m_field2;
        int m_field3;
    };
    int m_field4;
};
... AND the following snippet:
struct Parent
{
    struct
    {
        int m_field1;
        int m_field2;
        struct
        {
            int m_field3;
        };
    };
    int m_field4;
};
... both yield the same XML:
<compounddef>
    <!-- struct Parent -->
    <memberdef>
        <!-- int m_field1 -->
    </memberdef>
    <memberdef>
        <!-- int m_field2 -->
    </memberdef>
    <memberdef>
        <!-- int m_field3 -->
    </memberdef>
    <memberdef>
        <!-- unnamed member of type Parent::@0 -->
    </memberdef>
    <memberdef>
        <!-- int m_field4 -->
    </memberdef>
</compounddef>
I have omitted the gory details of the Doxygen XML, but it should be enough to demonstrate the point – Doxygen XML alone is simply ambiguous!
We have to somehow add extra information, but we don’t want a reader of our documentation to see that. Solution – \internal sections!
In your Doxyfile, add this alias:
INTERNAL_DOCS = YES
ALIASES += "unnamed{1}=\internal :unnamed(\1) \endinternal"
In your C/C++ code, add this special comment to the very first field of the unnamed struct:
struct Parent
{
    union
    {
        //! \unnamed{union}
        int m_field1;
        int m_field2;
    };
    int m_field3;
};
In case of nested unnamed structs, you have to also provide:
path to the field in the unnamed struct;
the number of fields in this unnamed struct.
struct Parent
{
    union
    {
        struct
        {
            //! \unnamed{union/struct:2}
            int m_field1;
            int m_field2;
        };
        struct
        {
            //! \unnamed{union/struct:3}
            int m_field2;
            int m_field3;
            int m_field4;
        };
    };
    int m_field5;
};
Note
It’s OK to inject \unnamed anywhere into a documentation block for the first member, for example:
//! This is documentation \unnamed{union} for m_field1