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 most accessible of the functions of that name, an overload set before a lone function, 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-comma-int, and at-1-int-const for at(int) const), and for function templates the number of template parameters (f-0-t1), then for their specializations the template arguments (make-0-t0-int). The other overload sets add their access and static (foo-protected-static), and using-declarations add using and the scope they name the member in (get-using-First, g-using-A-scope-B). 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.

A parameter's type is spelled as the function's type holds it: without a top-level const or volatile, since at(int const) declares the same function as at(int), and an array or a function as the pointer it is adjusted to, also inside a function type that a parameter is built from. Every punctuation character of a spelling becomes a word, such as scope for ::, lt and gt for < and >, comma, minus, ptr, ref, rref and pack, so that spellings which differ only in their punctuation stay apart: Offset<-1> and Offset<1>, Key<'$'> and Key<'@'>, or A<B<int>, C> and A<B<int, C>>. A comma also separates two parameters, or two template arguments, as in the source, so that f(long, long long) and f(long long, long) stay apart too. A parameter of type std::vector<int>& thus adds std-scope-vector-lt-int-gt-ref. An identifier outside ASCII is spelled whole. When the words that spell a signature, the arguments of a specialization, the target of a conversion function or the scope of a using-declaration would take more than 64 characters, they are replaced by h and the first eight hex digits of their xxh3 hash, which is the same on every platform.

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, 2namespace-alias, 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. No two kinds share a word, so that two members of different kinds that add their words never coincide. Every record adds class, whatever its key, so that turning a struct into a class does not change its anchor.

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.

Two cases are left as they are. Overloads that differ only in a dependent expression, such as f(Bits<~N>) and f(Bits<N>), are merged into one symbol before anchors are computed, so there is nothing for this PR to tell apart. And the adjustment of parameter types does not look inside the constraint of an auto type or inside a decltype. 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 spells parameter types as the function's type holds them, and 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. In javadoc/copydoc/decay-params, the function with an array parameter now gets the anchor foo-1-int-ptr, which spells the foo(int*) its own @copydoc names.
  • 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, a parameter with a top-level const next to a const member function, 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 function next to protected overloads, 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, specializations whose arguments differ only in a sign or in a character, overloads and specializations whose lists differ only in where one type ends, explicit specializations of a function template, overloads whose template arguments differ only in their nesting, overloads on types named outside ASCII, parameters declared as arrays and as functions, also inside a parameter of function pointer type, 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, a namespace next to a namespace alias whose name differs from it only in case, 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, two whose qualifiers differ only before their last component, and one whose qualifier is too long to spell. The without-overload-sets fixture pins the function called with no arguments keeping the plain name when overloads is off, and 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 89% 10247 9467 780 128 12 116 - -
🛠️ Source 11% 1231 1034 197 1 - 1 - -
📄 Docs <1% 23 23 - 1 - 1 - -
Total 100% 11501 10524 977 130 12 118 - -

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

🔝 Top Files

  • tests/golden/fixtures/config/legible-names/disambiguation.xml (Golden Tests): 4537 lines Δ (+4537 / -0)
  • tests/golden/fixtures/config/legible-names/disambiguation.adoc (Golden Tests): 1900 lines Δ (+1900 / -0)
  • tests/golden/fixtures/config/legible-names/using-declarations.xml (Golden Tests): 1557 lines Δ (+1557 / -0)

Generated by 🚫 dangerJS against be8332c

@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.44%. Comparing base (2d29928) to head (be8332c).

Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #1365   +/-   ##
========================================
  Coverage    83.44%   83.44%           
========================================
  Files           36       36           
  Lines         3861     3861           
  Branches       891      891           
========================================
  Hits          3222     3222           
  Misses         417      417           
  Partials       222      222           
Flag Coverage Δ
bootstrap 83.44% <ø> (ø)

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-11-13 17:18:06 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
@gennaroprota
gennaroprota force-pushed the feat/anchors_are_disambiguated_by_kind_and_signature branch from e2c6bf9 to ca3e416 Compare October 28, 2026 09:32
@gennaroprota
gennaroprota force-pushed the feat/anchors_are_disambiguated_by_kind_and_signature branch from ca3e416 to 9e274c5 Compare November 13, 2026 16:08
@coderabbitai

coderabbitai Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 130 files, which is 30 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: d5d28f24-8c2e-4a24-893e-6275d91208c5
Commits

Reviewing files that changed from the base of the PR and between 2d29928 and be8332c.

Files selected for processing: 130

  • docs/modules/ROOT/pages/configuration/output.adoc
  • src/mrdocs/Metadata/Finalizers/AnchorFinalizer.cpp
  • tests/golden/fixtures/config/auto-function-metadata/brief-from-function-class.xml
  • tests/golden/fixtures/config/auto-function-metadata/brief-from-operator.xml
  • tests/golden/fixtures/config/auto-function-metadata/param-from-function-class.xml
  • tests/golden/fixtures/config/auto-function-metadata/returns-from-special.xml
  • tests/golden/fixtures/config/extract-friends/extract-friends.xml
  • tests/golden/fixtures/config/extract-friends/no-extract-friends.xml
  • tests/golden/fixtures/config/extract-implicit-base-classes/extract-implicit-base-classes.xml
  • tests/golden/fixtures/config/extract-implicit-base-classes/no-extract-implicit-base-classes.xml
  • tests/golden/fixtures/config/inherit-base-members/base-overload-set.xml
  • tests/golden/fixtures/config/inherit-base-members/base-self-template.xml
  • tests/golden/fixtures/config/inherit-base-members/copy.xml
  • tests/golden/fixtures/config/inherit-base-members/redeclared-parameter-names.xml
  • tests/golden/fixtures/config/inherit-base-members/template-base.xml
  • tests/golden/fixtures/config/inherit-hidden-friends/copy-all.xml
  • tests/golden/fixtures/config/inherit-hidden-friends/copy-dependencies.xml
  • tests/golden/fixtures/config/inherit-hidden-friends/shapes/chain.xml
  • tests/golden/fixtures/config/inherit-hidden-friends/shapes/crtp-documented-base.xml
  • tests/golden/fixtures/config/inherit-hidden-friends/shapes/crtp-implementation-defined-base.xml
  • tests/golden/fixtures/config/inherit-hidden-friends/shapes/crtp-through-intermediate.xml
  • tests/golden/fixtures/config/inherit-hidden-friends/shapes/private-virtual-base.xml
  • tests/golden/fixtures/config/inherit-hidden-friends/shapes/shared-base.xml
  • tests/golden/fixtures/config/inherit-hidden-friends/shapes/specialization-operand-documented-base.xml
  • tests/golden/fixtures/config/inherit-hidden-friends/shapes/specialization-operand.xml
  • tests/golden/fixtures/config/inherit-hidden-friends/shapes/two-bases-dedup.xml
  • tests/golden/fixtures/config/legible-names/constructor.xml
  • tests/golden/fixtures/config/legible-names/disambiguation.adoc
  • tests/golden/fixtures/config/legible-names/disambiguation.cpp
  • tests/golden/fixtures/config/legible-names/disambiguation.xml
  • tests/golden/fixtures/config/legible-names/disambiguation.yml
  • tests/golden/fixtures/config/legible-names/using-declarations.cpp
  • tests/golden/fixtures/config/legible-names/using-declarations.xml
  • tests/golden/fixtures/config/legible-names/using-declarations.yml
  • tests/golden/fixtures/config/legible-names/without-overload-sets.cpp
  • tests/golden/fixtures/config/legible-names/without-overload-sets.xml
  • tests/golden/fixtures/config/legible-names/without-overload-sets.yml
  • tests/golden/fixtures/config/overloads/const-mutable.xml
  • tests/golden/fixtures/config/overloads/visibility.xml
  • tests/golden/fixtures/config/sfinae/base-cycle.xml
  • tests/golden/fixtures/config/sfinae/record-two-params.xml
  • tests/golden/fixtures/config/show-namespaces/show-namespaces.xml
  • tests/golden/fixtures/config/sort-members-by/sort-members-by-location.xml
  • tests/golden/fixtures/config/sort-members-by/sort-members-by-name.xml
  • tests/golden/fixtures/config/sort-namespace-members-by/sort-namespace-members-by-location.xml
  • tests/golden/fixtures/config/sort-namespace-members-by/sort-namespace-members-by-name.xml
  • tests/golden/fixtures/config/sort/sort-members.xml
  • tests/golden/fixtures/config/sort/unordered.xml
  • tests/golden/fixtures/config/warn-if-undocumented/warn-if-undocumented.xml
  • tests/golden/fixtures/filters/symbol-type/nested-private-template.xml
  • tests/golden/fixtures/generator/hbs/attributes/attributes.adoc
  • tests/golden/fixtures/generator/hbs/attributes/attributes.html
  • tests/golden/fixtures/generator/hbs/hidden-friend/hidden-friend.adoc
  • tests/golden/fixtures/javadoc/brief/brief-3.xml
  • tests/golden/fixtures/javadoc/copydoc/conversion.xml
  • tests/golden/fixtures/javadoc/copydoc/decay-params.xml
  • tests/golden/fixtures/javadoc/copydoc/fundamental.xml
  • tests/golden/fixtures/javadoc/copydoc/no-param.xml
  • tests/golden/fixtures/javadoc/copydoc/operator-param.xml
  • tests/golden/fixtures/javadoc/copydoc/param-types.xml
  • tests/golden/fixtures/javadoc/copydoc/qualified.xml
  • tests/golden/fixtures/javadoc/copydoc/qualifiers.xml
  • tests/golden/fixtures/javadoc/copydoc/template-arguments.xml
  • tests/golden/fixtures/javadoc/ref/parent_context.xml
  • tests/golden/fixtures/snippets/options/auto-function-metadata/auto-function-metadata.adoc
  • tests/golden/fixtures/snippets/options/extract-implicit-base-classes/extract-implicit-base-classes.adoc
  • tests/golden/fixtures/snippets/options/legible-names/legible-names.adoc
  • tests/golden/fixtures/snippets/options/legible-names/legible-names.cpp
  • tests/golden/fixtures/snippets/options/legible-names/legible-names.yml
  • tests/golden/fixtures/snippets/options/overloads/overloads.adoc
  • tests/golden/fixtures/snippets/options/sort-members-assignment-1st/sort-members-assignment-1st.adoc
  • tests/golden/fixtures/snippets/options/sort-members-conversion-last/sort-members-conversion-last.adoc
  • tests/golden/fixtures/snippets/options/sort-members-ctors-1st/sort-members-ctors-1st.adoc
  • tests/golden/fixtures/symbols/concept/requires-clause.xml
  • tests/golden/fixtures/symbols/function/conv-operator-names.xml
  • tests/golden/fixtures/symbols/function/doc-comment-macro-prefixed-inherited.xml
  • tests/golden/fixtures/symbols/function/explicit-conv-operator.xml
  • tests/golden/fixtures/symbols/function/explicit-ctor.xml
  • tests/golden/fixtures/symbols/function/explicit-object-parameter.xml
  • tests/golden/fixtures/symbols/function/macro-shared-comment.xml
  • tests/golden/fixtures/symbols/function/sfinae-out-of-line-definition.xml
  • tests/golden/fixtures/symbols/function/sfinae.xml
  • tests/golden/fixtures/symbols/function/spec-mem-implicit-instantiation.xml
  • tests/golden/fixtures/symbols/guide/explicit-deduct-guide.xml
  • tests/golden/fixtures/symbols/overloads/overloads-attributes.xml
  • tests/golden/fixtures/symbols/overloads/overloads-brief.xml
  • tests/golden/fixtures/symbols/overloads/overloads-metadata.xml
  • tests/golden/fixtures/symbols/overloads/overloads-ostream.xml
  • tests/golden/fixtures/symbols/overloads/overloads.xml
  • tests/golden/fixtures/symbols/record/class-template-array-spec.xml
  • tests/golden/fixtures/symbols/record/class-template-partial-spec.xml
  • tests/golden/fixtures/symbols/record/class-template-spec.xml
  • tests/golden/fixtures/symbols/record/class-template-specializations-1.xml
  • tests/golden/fixtures/symbols/record/class-template-specializations-2.xml
  • tests/golden/fixtures/symbols/record/class-template-specializations-3.xml
  • tests/golden/fixtures/symbols/record/conditional-explicit.xml
  • tests/golden/fixtures/symbols/record/dtor-overloads.xml
  • tests/golden/fixtures/symbols/record/friend-explicit-specialization.xml
  • tests/golden/fixtures/symbols/record/specialization-order.adoc
  • tests/golden/fixtures/symbols/record/specializations-and-guides.adoc
  • tests/golden/fixtures/symbols/record/template-specialization-inheritance.xml
  • tests/golden/fixtures/symbols/typedef/decay-to-primary.xml
  • tests/golden/fixtures/symbols/typedef/dependency-propagation.xml
  • tests/golden/fixtures/symbols/typedef/implicit-instantiation-member-ref.xml
  • tests/golden/fixtures/symbols/using/using-alias-template-dependent.xml
  • tests/golden/fixtures/symbols/using/using-function-after.xml
  • tests/golden/fixtures/symbols/using/using-function-and-type.xml
  • tests/golden/fixtures/symbols/using/using-function-local-overloads.xml
  • tests/golden/fixtures/symbols/using/using-function-overloads.xml
  • tests/golden/fixtures/symbols/using/using-member-conversion.xml
  • tests/golden/fixtures/symbols/using/using-member-function.xml
  • tests/golden/fixtures/symbols/variable/default-constructed-instance.xml
  • tests/golden/fixtures/symbols/variable/function-objects.xml
  • tests/golden/fixtures/symbols/variable/ns-variables.xml
  • tests/golden/fixtures/symbols/variable/static-data-template.xml
  • tests/golden/fixtures/symbols/variable/var-template.xml
  • tests/golden/fixtures/templates/c_mct_expl_inline.xml
  • tests/golden/fixtures/templates/c_mct_expl_outside.xml
  • tests/golden/fixtures/templates/c_mft_expl_inline.xml
  • tests/golden/fixtures/templates/c_mft_expl_outside.xml
  • tests/golden/fixtures/templates/ct_expl.xml
  • tests/golden/fixtures/templates/ct_mc_expl_outside.xml
  • tests/golden/fixtures/templates/ct_mct_expl_inline.xml
  • tests/golden/fixtures/templates/ct_mct_expl_outside.xml
  • tests/golden/fixtures/templates/ct_mf_expl_outside.xml
  • tests/golden/fixtures/templates/ct_mft_expl_inline.xml
  • tests/golden/fixtures/templates/ct_mft_expl_outside.xml
  • tests/golden/fixtures/templates/ft_expl.xml
  • tests/golden/fixtures/templates/implicit-specialization-dependency.adoc
  • tests/golden/fixtures/templates/implicit-specialization-dependency.xml

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@greptile-apps

greptile-apps Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; both previous findings are fixed and no new actionable issues remain.

Summary

This PR replaces symbol-ID suffixes with readable words that separate symbols by kind and signature.

  • Generated documentation uses readable kind and signature suffixes to separate colliding anchors.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Collect members of a scope] --> B[Group names ignoring case]
  B --> C[Choose who keeps the plain name]
  C --> D[Add kind and signature words]
  D --> E[Add symbol IDs for remaining ties]
  E --> F[Store each symbol's anchor]
  F --> G[Join parent anchors into links]
Loading

Reviews (3) · Last reviewed commit: "feat: anchors tell symbols that share a ..." · Reviewed by Greptile

@gennaroprota
gennaroprota force-pushed the feat/anchors_are_disambiguated_by_kind_and_signature branch from 9e274c5 to 1afd409 Compare November 13, 2026 16:44
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 (to the most accessible
of the functions of one name, 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-comma-int`, and
`at-1-int-const` for `at(int) const`). The other overload sets add their
access, followed by `static` if their functions are 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 1afd409 to be8332c Compare November 13, 2026 17:05

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