Open rouault opened 4 years ago
@jakobandersen At a glance i would think this is a problem at the Sphinx side, can you share thoughts?
I've tried a pure Sphinx workflow with index.rst being just
.. cpp:class:: MyClass
Bla
.. cpp:enum-class:: MyEnum
Bla
.. cpp:enumerator:: NONE
Bla
.. cpp:var:: const MyClass NONE
Bla
The above doesn't throw a warning. But if I replace .. cpp:enum-class:: MyEnum
by .. cpp:enum:: MyEnum
, I get a WARNING: Duplicate declaration, const MyClass NONE
warning, which is probably expected since the correspond C++ code wouldn't compile. So I believe this might be a Breathe issue, in that it likely emits a .. cpp:enum::
directive for a enum class. From what I can see in the Doxygen output when comparing a enum vs enum class, the later has a strong="yes" attribute in its <memberdef kind="enum" ....> element whereas the former has strong="no". So I guess Breathe should be able to use that to emit the proper Sphinx directive
I believe this is a Doxygen (and thereby Breathe) issue related to scoped vs. unscoped enumerations. When I run Doxygen (v1.8.13) I get the following XML for the enum:
<memberdef kind="enum" id="classcommon_1_1Foo_1a2889a8a66c3032f6179d172ae80dcd21" prot="public" static="no">
<name>Type</name>
<enumvalue id="classcommon_1_1Foo_1a2889a8a66c3032f6179d172ae80dcd21ab50339a10e1de285ac99d4c3990b8693" prot="public">
<name>NONE</name>
<briefdescription>
</briefdescription>
<detaileddescription>
<para>Enum value </para> </detaileddescription>
</enumvalue>
<briefdescription>
</briefdescription>
<detaileddescription>
<para>Enum Type </para> </detaileddescription>
<inbodydescription>
</inbodydescription>
<location file="test.hpp" line="7" column="1" bodyfile="test.hpp" bodystart="6" bodyend="10"/>
</memberdef>
Maybe I missed it somewhere, or my Doxygen is too old, but basically the handling need to be done at https://github.com/michaeljones/breathe/blob/master/breathe/renderer/sphinxrenderer.py#L1453 where handle_declaration
needs to get obj_type='enum-struct'
or obj_type='enum-class'
instead of the default obj_type=None
if the enum is scoped.
As another note, for helping debugging this type of issue:
In the beginning of sphinxrenderer.py
there are 3 new variables for printing debug info (they should probably be available to set in a project configuration, but I didn't immediately find out how to do that when I added them). If you set debug_trace_directives = True
you get info about the directives that are actually seen by the Sphinx domains, including nesting. In this case:
Running directive: .. cpp:type:: common
Running directive: .. cpp:class:: Foo
Running directive: .. cpp:enum:: Type
Running directive: .. cpp:enumerator:: NONE
Running directive: .. cpp:var:: const Foo NONE
so from that we can also see that it is not a direct clash of declarations, but very likely because Type::None
is added to the parent scope due to the enum being unscoped.
In Sphinx there is a similar debug variable to print the complete symbols trees (debug_show_tree
), so for the fun of it, it gives:
::
common: common (index)
Foo: Foo (index)
Type: Type (index)
NONE: NONE (index)
NONE: NONE (index)
NONE: !!duplicate!! const Foo NONE (index)
Yes Doxygen version must matter. With 1.8.17, I get
<memberdef kind="enum" id="classcommon_1_1Foo_1a2889a8a66c3032f6179d172ae80dcd21" prot="public" static="no" strong="yes">
<type></type>
<name>Type</name>
<enumvalue id="classcommon_1_1Foo_1a2889a8a66c3032f6179d172ae80dcd21ab50339a10e1de285ac99d4c3990b8693" prot="public">
<name>NONE</name>
<briefdescription>
</briefdescription>
<detaileddescription>
<para>Enum value </para>
</detaileddescription>
</enumvalue>
<briefdescription>
</briefdescription>
<detaileddescription>
<para>Enum Type </para>
</detaileddescription>
<inbodydescription>
</inbodydescription>
<location file="test.hpp" line="7" column="1" bodyfile="test.hpp" bodystart="6" bodyend="10"/>
</memberdef>
I've spotted a 4.16.0 -> 4.17.0 regression regarding a confusion when a enum class enumerator and a static variable share the same name
Minimum reproducer:
given test.hpp with
given conf.py with
breathe_projects = { "doxygen_api": "xml/" }
.. doxygennamespace:: common :project: doxygen_api :members: