Skip to content

feat: anchors tell symbols that share a name apart by kind and signature - #1365

Open
gennaroprota wants to merge 1 commit into
cppalliance:developfrom
gennaroprota:feat/anchors_are_disambiguated_by_kind_and_signature
Open

gennaroprota wants to merge 1 commit into
cppalliance:developfrom
gennaroprota:feat/anchors_are_disambiguated_by_kind_and_signature

Conversation

@gennaroprota

@gennaroprota gennaroprota commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

With legible-names, symbols of one scope that share a name, ignoring case, were told apart by a suffix taken from their symbol IDs: an overload set of abs and its two functions got abs-043, abs-04b and abs-01. The suffix meant nothing to a reader, changed whenever the IDs did (as they can on a Clang upgrade, or with an unrelated configuration change, as #1308 shows), and appeared, or grew longer, when one more symbol of that name joined the scope. Links into the documentation broke although nothing they pointed to had changed.

This PR implements the scheme #1288 proposes, with the symbol kind as an extra step for the case #1308 reports. At most one of the members that share a name keeps it: the overload set (the most accessible one, when a class splits them by access), the primary template, or, between symbols of different kinds, the kind that comes first, such as a class next to a concept. Each of the others adds the words that tell it apart: its kind (Quantity-concept), the number of its parameters or template arguments (resize-1), then their types and qualifiers (resize-2-double-int, at-1-int-const), and for function templates the number of template parameters (f-0-t1). The other overload sets add their access and static (foo-protected-static), and using-declarations add using and the class they name the member in (get-using-First). A conversion function is named after the type it converts to (2conversion-int), so adding one no longer renames the others. A new symbol thus changes only the anchors of the symbols it has to be told apart from, and turning on extract-private no longer changes the anchor of the public overload set, or of a public function with no public overloads. Between two functions of one name and access with no overloads, one static and one not, the non-static one keeps the name, as between overload sets.

Each suffix starts with a keyword or a digit, so it can never be the name of a member, whose anchor follows its parent's after a - in a single-page fragment. The words that start with a digit (2function, 2variable, 2guide, 2enumerator, 2macro) follow the reserved names MrDocs already gives to special functions, such as 2constructor; the other kind words (class, enum, typedef, concept, using, namespace) and the access words are keywords. Every record adds class, whatever its key, so that turning a struct into a class does not change its anchor. The abbreviations ref, rref, ptr, pack and tN keep anchors short, and a spelled signature or conversion target longer than 64 characters is replaced by h and the first eight hex digits of its xxh3 hash, which is the same on every platform.

Names are still compared ignoring case, so that two anchors never collide as files on a case-insensitive filesystem. The symbol ID remains the suffix of last resort, for symbols that nothing else tells apart: overloads and specializations that differ only in their constraints, names of one kind that differ only in case, redefined macros, several unnamed records in one scope, copies of inherited members with the same signature.

A per-symbol anchor override, which #1308 also asks for, is left for a follow-up.

Changes

  • Source: src/mrdocs/Metadata/Finalizers/AnchorFinalizer.cpp settles the anchors of each scope together: it groups the members that share a name, ranks their kinds, picks the member that keeps the name, and gives the others the fewest parts of their signature that tell them apart. It also names conversion functions after the type they convert to.
  • Golden tests: New fixtures config/legible-names/disambiguation, using-declarations and without-overload-sets, and a legible-names options snippet. The existing goldens with colliding names or with conversion functions are regenerated; in each of them only the anchors of those symbols change, apart from a blank line that the current generator writes in sort-members-ctors-1st.adoc and the test harness ignores.
  • Breaking changes: The anchors, and in multipage output the file names, of every symbol that shares its name with another and of every conversion function change, so existing links to those pages break once.

Testing

The disambiguation fixture pins the anchors of overloads, const overloads, conversion functions (two of them to one type, and one to a type too long to spell), overload sets that a class splits by access, a public and a protected function of one name, a static and a non-static function of one name, overloads whose signatures are too long to spell, class template specializations, a class next to a concept whose name differs only in case, a struct next to a function, deduction guides, a struct named like the global index, and a class next to both an alias-declaration whose name differs from it only in case and a using-declaration of its own name. The using-declarations fixture pins using-declarations of one name, including one with no qualifier, and the without-overload-sets fixture the function called with no arguments keeping the plain name when overloads is off. The visibility fixture pins overload sets split by access and by static. Every anchor removed from the regenerated goldens is an old symbol-ID anchor or the old anchor of a conversion function.

Documentation

configuration/output.adoc describes how colliding names are told apart, next to its mention of legible-names, with an example taken from the new options snippet.

Fixes #1288.
Fixes #1308.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

✨ Highlights

  • 🧪 Existing golden tests changed (behavior likely shifted)

🧾 Changes by Scope

Scope Lines Δ% Lines Δ Lines + Lines - Files Δ Files + Files ~ Files ↔ Files -
🥇 Golden Tests 86% 6454 5674 780 128 12 116 - -
🛠️ Source 14% 1040 844 196 1 - 1 - -
📄 Docs <1% 21 21 - 1 - 1 - -
Total 100% 7515 6539 976 130 12 118 - -

Legend: Files + (added), Files ~ (modified), Files ↔ (renamed), Files - (removed)

🔝 Top Files

  • tests/golden/fixtures/config/legible-names/disambiguation.xml (Golden Tests): 2470 lines Δ (+2470 / -0)
  • tests/golden/fixtures/config/legible-names/disambiguation.adoc (Golden Tests): 1044 lines Δ (+1044 / -0)
  • src/mrdocs/Metadata/Finalizers/AnchorFinalizer.cpp (Source): 1040 lines Δ (+844 / -196)

Generated by 🚫 dangerJS against ca3e416

@codecov

codecov Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.21%. Comparing base (9faf2d7) to head (ca3e416).

Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #1365   +/-   ##
========================================
  Coverage    83.21%   83.21%           
========================================
  Files           35       35           
  Lines         3670     3670           
  Branches       845      845           
========================================
  Hits          3054     3054           
  Misses         410      410           
  Partials       206      206           
Flag Coverage Δ
bootstrap 83.21% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@gennaroprota
gennaroprota force-pushed the feat/anchors_are_disambiguated_by_kind_and_signature branch from 7809d8c to c467fb7 Compare October 22, 2026 13:50
@cppalliance-bot

cppalliance-bot commented Oct 22, 2026 •

Copy link
Copy Markdown

An automated preview of the documentation is available at https://1365.mrdocs.prtest2.cppalliance.org/index.html

If more commits are pushed to the pull request, the docs will rebuild at the same URL.

2026-10-28 09:52:40 UTC

@gennaroprota
gennaroprota force-pushed the feat/anchors_are_disambiguated_by_kind_and_signature branch from c467fb7 to e2c6bf9 Compare October 22, 2026 14:17
With `legible-names`, symbols of one scope that share a name, ignoring
case, were told apart by a suffix taken from their symbol IDs: an
overload set of `abs` and its two functions got `abs-043`, `abs-04b` and
`abs-01`. The suffix meant nothing to a reader. It changed whenever the
IDs did, as they can on a Clang upgrade or with an unrelated
configuration change, and it appeared, or grew longer, when one more
symbol of that name joined the scope, so links into the documentation
broke although nothing they pointed to had changed.

We now give the plain name to the overload set, the most accessible one
when a class splits them by access, to the primary template, or, between
symbols of different kinds, to the kind that comes first, such as a
class next to a concept. Each of the others adds the words that tell it
apart: its kind (`Quantity-concept`), the number of its parameters or
template arguments (`resize-1`), then their types and the qualifiers
(`resize-2-double-int`, `at-1-int-const`). The other overload sets add
their access and `static`, and using-declarations add `using` and the
class they name the member in. A conversion function is named after the
type it converts to (`2conversion-int`), so only conversions to one type
share a name. A new symbol thus changes only the anchors of the symbols
it has to be told apart from.

Each suffix starts with a keyword or a digit, so it can never be the
name of a member, whose anchor follows its parent's after a `-` in a
single-page fragment. The symbol ID remains the suffix of last resort,
for symbols that nothing else tells apart, such as overloads that differ
only in their constraints, or classes whose names differ only in case.

Note that anchors change, and with them the file names of multipage
output, for every symbol that shares its name with another and for every
conversion function, so existing links to those pages break once.

Fixes cppalliance#1288.
Fixes cppalliance#1308.
@gennaroprota
gennaroprota force-pushed the feat/anchors_are_disambiguated_by_kind_and_signature branch from e2c6bf9 to ca3e416 Compare October 28, 2026 09:32

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants