breathe icon indicating copy to clipboard operation
breathe copied to clipboard

Duplicate definition with C "typedef struct foo foo"

Open Shamino0 opened this issue 4 years ago • 3 comments

The following concept is perfectly valid C code:

typedef struct foo_t {
   int bar;
} foo_t;

For a C++ project, of course, the typedef is redundant, but for a C project, it is not. foo_t and struct foo_t are two distinct items.

Doxygen renders this correctly, putting the foo_t documentation in a "Typedef Documentation" section and struct foo_t in a "Data Structures" section. The typedef has a link to the structure.

When I use Breathe to embed the header's documentation into a Sphinx file with

.. doxygenfile:: foo.h
   :project: MYPROJECT

it generates a warning, saying that foo_t is a duplicate definition:

.../mydoc.rst: 9: WARNING: Duplicate declaration, foo_t

In the Sphinx-generated HTML output, I do see the two items listed in their proper sections. foo_t in the "Typedefs" section and struct foo_t in the (unlabeled) structures section, but I can only link to the typedef. References to :c:type:`foo_t` correctly links to the foo_t typedef, but references to :c:struct:`foo_t` links to the same location (it should link to the struct foo_t structure).

This problem does not happen if the struct and the typedef use different symbols:

typedef struct foo_s {
   int bar;
} foo_t;

but I shouldn't have to make such a change in my code. It is perfectly valid C for the struct name and the typedef name to be the same.

I also understand that this should be a problem in C++, where the typedef is redundant. But I've explicitly configured Breathe to use the C domain, so it should know that this is not C++ code:

breathe_domain_by_extension = { "h" : "c" }

Somewhere in Breathe, the code does not distinguish between different C language constructs that share the same name. For example, all of the following are distinct language elements:

  • typedef ... foo_t - referenceable via :c:type:`foo_t`
  • struct foo_t - referenceable via :c:struct:`foo_t`
  • union foo_t - referenceable via :c:union:`foo_t`
  • enum foo_t - referenceable via :c:enum:`foo_t`

I'm not sure what the best fix is, but please see if there is something that can be done.

Shamino0 avatar Jun 11 '20 15:06 Shamino0

There may be a minor change needed in Breathe, but otherwise the core problem is in Sphinx. I have opened an issue over there to discuss what the behaviour should be. I tried double checking that this is not a regression with Sphinx v3.x and and the newer versions of Breathe, but in this example I couldn't get it to insert the struct, only the typedef (though in a raw Sphinx file it seems indeed like it is not a regression). Can you try in your project with Sphinx 2.4.4 and an older Breathe version (v4.14.2?) and see which results you get? It may not spit out a duplication warning, but when you hover near a duplicate declaration in the HTML there will be no permalink shown.

jakobandersen avatar Jun 11 '20 15:06 jakobandersen

Thanks. You are correct - it appears to be a Sphinx problem. I produced a test-case (attached) that demonstrates this (tested with Sphinx 3.1.0 and Breathe 4.19.0)

testcase.zip

I'll see if I can revert to older versions and see if anything changes.

Shamino0 avatar Jun 11 '20 19:06 Shamino0

Unfortunately, installing older versions doesn't seem to work. Installing Sphinx 2.4.4 via pip3 seems to end up installing 3.1.0 anyway (or something broken that reports itself as 3.1.0). Likewise with older versions of Breathe. I'm not sure what the cause is, but the result crashes:

Running Sphinx v3.1.0
making output directory... done
building [mo]: targets for 0 po files that are out of date
building [html]: targets for 3 source files that are out of date
updating environment: [new config] 3 added, 0 changed, 0 removed
reading sources... [ 33%] foo                                                                                                                                
Exception occurred:
  File "/home/qca/.local/lib/python3.6/site-packages/sphinx/domains/c.py", line 3093, in object_type
    raise NotImplementedError()
NotImplementedError
The full traceback has been saved in /tmp/sphinx-err-bpeadj_k.log, if you want to report the issue to the developers.
Please also report this if it was a user error, so that a better error message can be provided next time.
A bug report can be filed in the tracker at <https://github.com/sphinx-doc/sphinx/issues>. Thanks!
Makefile:25: recipe for target 'html' failed
make: *** [html] Error 2

Shamino0 avatar Jun 11 '20 20:06 Shamino0