Skip to content

Tagfile output omits OverloadsSymbol entries for member overload sets #1201

Description

@alandefreitas

When MrDocs generates a tagfile for a record that contains an overloaded member function, the resulting <tagfile> has no entry for the overload set. Neither a top-level <compound kind="class"> for the OverloadsSymbol nor a <member kind="function"> inside the parent class compound is emitted. Consumers of the tagfile (e.g. @cppalliance/antora-cpp-tagfiles-extension) cannot resolve a reference like boost::urls::url_view_base::params to the overload set page, and fall back to the parent class page.

This was originally reported against the tagfiles extension in cppalliance/antora-cpp-tagfiles-extension#4, but the root cause is in MrDocs.

Reproducer

Use the existing test-files/golden-tests/symbols/overloads/overloads-metadata.cpp sample (or any record that has at least one overloaded member function), generate the tagfile, and grep for the overload-set name. The <member> and <compound> entries for it are missing.

Live example: in the published Boost.URL documentation, the page

https://www.boost.org/doc/libs/latest/doc/antora/url/reference/boost/urls/url_view_base/params-065.html

exists and is the canonical overload-set page for url_view_base::params, but the generated tagfile contains no entry that points there.

Root cause

In src/lib/Gen/hbs/TagfileWriter.cpp:

  1. TagfileWriter::operator() dispatches by kind. Namespaces go to writeNamespace; anything that is !isFunction() goes to writeClassLike; FunctionSymbols are written via writeFunctionMember inside the parent's traversal.
  2. writeNamespace calls corpus_->traverse(I, fn) on the namespace and invokes operator()(J) on every direct member. This writes records and sub-namespaces as their own top-level compounds.
  3. writeClassLike(record) iterates the record's members with corpus_->traverse(record, fn) and only writes a <member> for those where U::isFunction() is true. After OverloadsFinalizer runs, the record's Members.Functions list contains an OverloadsSymbol (kind = Overloads, not Function) in place of the individual overloaded FunctionSymbols. The OverloadsSymbol is therefore skipped, and its Members (the individual FunctionSymbols) are never reached.
  4. corpus_->traverse does not recurse through this code path. The recursive call traverse(opts, *MI, f, args...) is templated on T = Symbol (the base class). The constexpr branch is gated by SymbolParent<T>, which requires allMembers(Symbol const&) to be a valid expression. No such overload exists for the base Symbol class, so SymbolParent<Symbol> is false and the recursion compiles to a no-op.

The net effect is that OverloadsSymbols nested inside records are never visited by the tagfile writer and never appear in the output.

Suggested fix

Either of these would let downstream tagfile consumers resolve the reference correctly. The first option is preferable because it matches what is already done for records and namespaces, and the URL of the overload-set page is what users actually want to link to.

Option A — write OverloadsSymbol as a top-level compound. Extend writeNamespace (or add a dedicated path) so that for each OverloadsSymbol reachable inside a record, a top-level entry like the following is emitted:

<compound kind="class">
  <name>boost::urls::url_view_base::params</name>
  <filename>boost/urls/url_view_base/params-065.adoc</filename>
</compound>

The simplest way is probably to walk records explicitly while visiting a namespace and write overload-set compounds for each overloaded member, using corpus_->qualifiedName(O) for the name and generateFilename(O) for the filename.

Option B — write each OverloadsSymbol as a <member kind="function"> inside its parent class compound, with the overload-set page as <anchorfile>:

<member kind="function">
  <name>params</name>
  <anchorfile>boost/urls/url_view_base/params-065.adoc</anchorfile>
  <anchor></anchor>
</member>

Doxygen tagfile consumers will pick up the first such <member> for a name and use its anchorfile, so the overload-set landing page is what gets linked.

Whichever option is chosen, the data needs to be present in the tagfile; downstream consumers cannot infer the qualified ID suffix (e.g. -065) from the symbol name alone.

Verification on the consumer side

I verified that the existing lookup in antora-cpp-tagfiles-extension/lib/extension.js (getSymbolFilename) resolves correctly as soon as either form above is present in the tagfile. With the current MrDocs output the same lookup falls back to the class's filename, which is the symptom described in antora-cpp-tagfiles-extension#4.

Metadata

Metadata

Assignees

No one assigned

    Labels

    fixSomething that is broken / incorrect behavior

    Type

    No type

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions