Skip to content

Commit ff4f6fc

Browse files
committed
feat: move template specializations and deduction guides off parent scope page
Class template specializations, function template specializations, and deduction guides used to share the enclosing scope's listing with their primary template. Users have repeatedly reported this as confusing: `vector` and `vector<int>` appearing side by side in the namespace index reads as if they were independent siblings, and a primary's variants were nowhere on its own page. Specializations now appear in a dedicated "Specializations" section on the primary's documentation page, and deduction guides in a "Deduction Guides" section on the deduced class's page. The parent scope's listing carries only the primary itself. An orphan specialization (one whose primary has been excluded from extraction) stays in the parent's listing so the index can still reach it. The relationship is stored in the corpus: each primary record or function template carries the IDs of its specializations (and, for class templates, of its deduction guides), and each specialization carries an `IsSpecialization` flag. The lists are populated by a finalizer pass and exposed via reflection, so the XML output gains matching `<specializations>`, `<deduction-guides>`, and `<is-specialization>` elements and the DOM/Handlebars layer renders the new sections through plain field access. Closes issue #1154.
1 parent 74bf1a3 commit ff4f6fc

110 files changed

Lines changed: 2984 additions & 492 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

include/mrdocs/Metadata/Symbol/Function.hpp

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <mrdocs/Metadata/Symbol/SymbolBase.hpp>
2323
#include <mrdocs/Metadata/Template.hpp>
2424
#include <mrdocs/Support/Describe.hpp>
25+
#include <mrdocs/Support/MapReflectedType.hpp>
2526
#include <string>
2627
#include <vector>
2728

@@ -137,6 +138,36 @@ struct FunctionSymbol final
137138
*/
138139
Optional<SymbolID> FunctionObjectImpl;
139140

141+
/** Whether this function is listed on its primary's page.
142+
143+
A presentation-layer flag set by `SpecializationFinalizer`
144+
when *both* conditions hold:
145+
146+
1. This function is a template specialization (AST-local,
147+
equivalent to `Template->specializationKind() != Primary`).
148+
2. Its primary is being extracted in
149+
@ref ExtractionMode::Regular (cross-symbol, needs the
150+
corpus).
151+
152+
When set, the function is rendered in its primary's
153+
"Specializations" section and suppressed from the parent
154+
scope's listing. Orphan specializations (primary excluded
155+
from extraction) fail condition 2 and keep the flag `false`,
156+
so they remain reachable from the parent scope. The name
157+
deliberately encodes the resulting placement rather than
158+
the AST property in 1, which `Template` already exposes.
159+
*/
160+
bool IsListedOnPrimary = false;
161+
162+
/** Specializations whose primary is this function.
163+
164+
Populated by `SpecializationFinalizer` with the IDs of
165+
function-template specializations referring to this
166+
function as their primary. Sorted by referent name
167+
then ID.
168+
*/
169+
std::vector<SymbolID> Specializations;
170+
140171
//--------------------------------------------
141172

142173
/** Construct a function symbol with its ID.
@@ -161,7 +192,8 @@ MRDOCS_DESCRIBE_STRUCT(
161192
IsNodiscard, IsExplicitObjectMemberFunction, Constexpr,
162193
OverloadedOperator, StorageClass, IsRecordMethod, IsVirtual,
163194
IsVirtualAsWritten, IsPure, IsConst, IsVolatile, IsFinal,
164-
RefQualifier, Explicit, Attributes, FunctionObjectImpl)
195+
RefQualifier, Explicit, Attributes, FunctionObjectImpl,
196+
IsListedOnPrimary, Specializations)
165197
)
166198

167199
/** Map a vector of parameters to a @ref dom::Value object.

include/mrdocs/Metadata/Symbol/Record.hpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66
//
77
// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com)
8+
// Copyright (c) 2026 Gennaro Prota (gennaro.prota@gmail.com)
89
//
910
// Official repository: https://github.com/cppalliance/mrdocs
1011
//
@@ -74,6 +75,43 @@ struct RecordSymbol final
7475
*/
7576
std::vector<FriendInfo> Friends;
7677

78+
/** Whether this record is listed on its primary's page.
79+
80+
A presentation-layer flag set by `SpecializationFinalizer`
81+
when *both* conditions hold:
82+
83+
1. This record is a template specialization (AST-local,
84+
equivalent to `Template->specializationKind() != Primary`).
85+
2. Its primary is being extracted in
86+
@ref ExtractionMode::Regular (cross-symbol, needs the
87+
corpus).
88+
89+
When set, the record is rendered in its primary's
90+
"Specializations" section and suppressed from the parent
91+
scope's listing. Orphan specializations (primary excluded
92+
from extraction) fail condition 2 and keep the flag `false`,
93+
so they remain reachable from the parent scope. The name
94+
deliberately encodes the resulting placement rather than
95+
the AST property in 1, which `Template` already exposes.
96+
*/
97+
bool IsListedOnPrimary = false;
98+
99+
/** Specializations whose primary is this record.
100+
101+
Populated by `SpecializationFinalizer` with the IDs of
102+
class-template specializations referring to this record
103+
as their primary. Sorted by referent name then ID.
104+
*/
105+
std::vector<SymbolID> Specializations;
106+
107+
/** Deduction guides associated with this class template.
108+
109+
Populated by `SpecializationFinalizer` with the IDs of
110+
deduction guides that deduce this record. Sorted by
111+
referent name then ID.
112+
*/
113+
std::vector<SymbolID> DeductionGuides;
114+
77115
//--------------------------------------------
78116

79117
/** Create a record symbol bound to an ID.
@@ -93,7 +131,8 @@ MRDOCS_DESCRIBE_STRUCT(
93131
RecordSymbol,
94132
(SymbolCommonBase<SymbolKind::Record>),
95133
(KeyKind, Template, IsTypeDef, IsFinal, IsFinalDestructor,
96-
Bases, Derived, Interface, Friends)
134+
Bases, Derived, Interface, Friends,
135+
IsListedOnPrimary, Specializations, DeductionGuides)
97136
)
98137

99138
/** Return the default accessibility for a record key kind.

mrdocs.rnc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,10 @@ grammar
370370
BaseInfo*,
371371
element derived { SymbolID }*,
372372
RecordInterface?,
373-
FriendInfo*
373+
FriendInfo*,
374+
element is-listed-on-primary { Bool }?,
375+
element specializations { SymbolID }*,
376+
element deduction-guides { SymbolID }*
374377
}
375378

376379
BaseInfo =
@@ -445,7 +448,9 @@ grammar
445448
element ref-qualifier { text }?,
446449
element explicit { text }?,
447450
element attributes { text }*,
448-
element function-object-impl { SymbolID }?
451+
element function-object-impl { SymbolID }?,
452+
element is-listed-on-primary { Bool }?,
453+
element specializations { SymbolID }*
449454
}
450455

451456
#---------------------------------------------

share/mrdocs/addons/generator/adoc/partials/symbol.adoc.hbs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,16 @@
145145
{{/each}}
146146
|===
147147

148+
{{/if}}
149+
{{! Specializations of this primary template }}
150+
{{#if symbol.specializations}}
151+
{{>symbol/members-table members=symbol.specializations title="Specializations"}}
152+
153+
{{/if}}
154+
{{! Deduction guides for this class template }}
155+
{{#if symbol.deductionGuides}}
156+
{{>symbol/members-table members=symbol.deductionGuides title="Deduction Guides"}}
157+
148158
{{/if}}
149159
{{! Using symbols }}
150160
{{#if symbol.shadowDeclarations}}

share/mrdocs/addons/generator/common/partials/symbol/tranche.hbs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
88
Each value in the tranche is a list of symbols that belong to the tranche.
99
10+
Template specializations and deduction guides are filtered out: they are
11+
listed instead on the primary template's own page, via the dedicated
12+
"Specializations" / "Deduction Guides" sections.
13+
1014
Expected Context: {Tranche Object}
1115
1216
Example:
@@ -17,21 +21,20 @@
1721
{{#if is-namespace}}
1822
{{>symbol/members-table members=tranche.namespaces title="Namespaces"}}
1923
{{>symbol/members-table members=tranche.namespaceAliases title="Namespace Aliases"}}
20-
{{>symbol/members-table members=(concat tranche.records tranche.typedefs) title=(concat (select label (concat label " ") "") "Types")}}
24+
{{>symbol/members-table members=(concat (filter_out tranche.records "isListedOnPrimary") tranche.typedefs) title=(concat (select label (concat label " ") "") "Types")}}
2125
{{>symbol/members-table members=tranche.enums title=(concat (select label (concat label " ") "") "Enums")}}
22-
{{>symbol/members-table members=tranche.functions title="Functions"}}
26+
{{>symbol/members-table members=(filter_out tranche.functions "isListedOnPrimary") title="Functions"}}
2327
{{>symbol/members-table members=tranche.variables title="Variables"}}
2428
{{>symbol/members-table members=tranche.concepts title="Concepts"}}
25-
{{>symbol/members-table members=tranche.guides title=(concat (select label (concat label " ") "") "Deduction Guides")}}
2629
{{>symbol/members-table members=tranche.usings title=(concat (select label (concat label " ") "") "Using Declarations")}}
2730
{{else}}
2831
{{>symbol/members-table members=tranche.namespaceAliases title="Namespace Aliases"}}
29-
{{>symbol/members-table members=(concat tranche.records tranche.typedefs) title=(concat (select label (concat label " ") "") "Types")}}
32+
{{>symbol/members-table members=(concat (filter_out tranche.records "isListedOnPrimary") tranche.typedefs) title=(concat (select label (concat label " ") "") "Types")}}
3033
{{>symbol/members-table members=tranche.enums title=(concat (select label (concat label " ") "") "Enums")}}
31-
{{>symbol/members-table members=tranche.functions title=(concat (select label (concat label " ") "") "Member Functions")}}
32-
{{>symbol/members-table members=tranche.staticFunctions title=(concat (select label (concat label " ") "") "Static Member Functions")}}
34+
{{>symbol/members-table members=(filter_out tranche.functions "isListedOnPrimary") title=(concat (select label (concat label " ") "") "Member Functions")}}
35+
{{>symbol/members-table members=(filter_out tranche.staticFunctions "isListedOnPrimary") title=(concat (select label (concat label " ") "") "Static Member Functions")}}
3336
{{>symbol/members-table members=tranche.variables title=(concat (select label (concat label " ") "") "Data Members")}}
3437
{{>symbol/members-table members=tranche.staticVariables title=(concat (select label (concat label " ") "") "Static Data Members")}}
3538
{{>symbol/members-table members=tranche.aliases title=(concat (select label (concat label " ") "") "Aliases")}}
3639
{{>symbol/members-table members=tranche.usings title=(concat (select label (concat label " ") "") "Using Declarations")}}
37-
{{/if}}
40+
{{/if}}

share/mrdocs/addons/generator/html/partials/symbol.html.hbs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,18 @@
192192
</table>
193193
</div>
194194
{{/if}}
195+
{{! Specializations of this primary template }}
196+
{{#if symbol.specializations}}
197+
<div>
198+
{{>symbol/members-table members=symbol.specializations title="Specializations"}}
199+
</div>
200+
{{/if}}
201+
{{! Deduction guides for this class template }}
202+
{{#if symbol.deductionGuides}}
203+
<div>
204+
{{>symbol/members-table members=symbol.deductionGuides title="Deduction Guides"}}
205+
</div>
206+
{{/if}}
195207
{{! Using symbols }}
196208
{{#if symbol.shadowDeclarations}}
197209
<div>

src/lib/CorpusImpl.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <lib/AST/MissingSymbolSink.hpp>
1717
#include <lib/AST/MrDocsFileSystem.hpp>
1818
#include <lib/Metadata/Finalizers/BaseMembersFinalizer.hpp>
19+
#include <lib/Metadata/Finalizers/SpecializationFinalizer.hpp>
1920
#include <lib/Metadata/Finalizers/DerivedFinalizer.hpp>
2021
#include <lib/Metadata/Finalizers/DocCommentFinalizer.hpp>
2122
#include <lib/Metadata/Finalizers/FunctionObjectFinalizer.hpp>
@@ -1078,6 +1079,14 @@ CorpusImpl::finalize()
10781079
finalizer.build();
10791080
}
10801081

1082+
// Populate primary -> specialization back-pointers
1083+
// and the deduction-guide lists on deduced records.
1084+
{
1085+
report::debug(" - Finalizing specializations");
1086+
SpecializationFinalizer finalizer(*this);
1087+
finalizer.build();
1088+
}
1089+
10811090
// Sort members: this runs unconditionally because
10821091
// the members of some symbol types are always sorted.
10831092
{

src/lib/CorpusImpl.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class CorpusImpl final : public Corpus
6464
friend class NamespacesFinalizer;
6565
friend class DerivedFinalizer;
6666
friend class FunctionObjectFinalizer;
67+
friend class SpecializationFinalizer;
6768

6869
public:
6970
/** Constructor.

0 commit comments

Comments
 (0)