Skip to content

Commit ea513c9

Browse files
committed
Records store friends as relationships
#feat
1 parent 78a4394 commit ea513c9

File tree

80 files changed

+573
-1125
lines changed

Some content is hidden

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

80 files changed

+573
-1125
lines changed

include/mrdocs/Metadata/Info/Enum.hpp

-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
#include <mrdocs/Metadata/Source.hpp>
1818
#include <mrdocs/Metadata/Type.hpp>
1919
#include <mrdocs/Dom/LazyArray.hpp>
20-
#include <ranges>
2120

2221
namespace clang::mrdocs {
2322

include/mrdocs/Metadata/Info/Friend.hpp

+12-17
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,20 @@
1818
namespace clang::mrdocs {
1919

2020
/** Info for friend declarations.
21+
22+
- Friendship is not transitive
23+
- Friendship is not inherited
24+
- Access specifiers have no effect on the meaning of friend declarations
2125
*/
2226
struct FriendInfo final
23-
: InfoCommonBase<InfoKind::Friend>
2427
{
2528
/** Befriended symbol.
2629
*/
27-
SymbolID FriendSymbol = SymbolID::invalid;
30+
SymbolID id = SymbolID::invalid;
2831

2932
/** Befriended type.
3033
*/
31-
Polymorphic<TypeInfo> FriendType;
32-
33-
//--------------------------------------------
34-
35-
explicit FriendInfo(SymbolID ID) noexcept
36-
: InfoCommonBase(ID)
37-
{
38-
}
34+
Polymorphic<TypeInfo> Type;
3935
};
4036

4137
MRDOCS_DECL
@@ -52,20 +48,19 @@ tag_invoke(
5248
FriendInfo const& I,
5349
DomCorpus const* domCorpus)
5450
{
55-
tag_invoke(t, io, dynamic_cast<Info const&>(I), domCorpus);
56-
if (I.FriendSymbol)
51+
if (I.id)
5752
{
5853
io.defer("name", [&I, domCorpus]{
59-
return dom::ValueFrom(I.FriendSymbol, domCorpus).get("name");
54+
return dom::ValueFrom(I.id, domCorpus).get("name");
6055
});
61-
io.map("symbol", I.FriendSymbol);
56+
io.map("symbol", I.id);
6257
}
63-
else if (I.FriendType)
58+
else if (I.Type)
6459
{
6560
io.defer("name", [&]{
66-
return dom::ValueFrom(I.FriendType, domCorpus).get("name");
61+
return dom::ValueFrom(I.Type, domCorpus).get("name");
6762
});
68-
io.map("type", I.FriendType);
63+
io.map("type", I.Type);
6964
}
7065
}
7166

include/mrdocs/Metadata/Info/InfoNodes.inc

-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ INFO(Enum)
2020
INFO(EnumConstant)
2121
INFO(Typedef)
2222
INFO(Variable)
23-
INFO(Friend)
2423
INFO(Guide)
2524
INFO(NamespaceAlias)
2625
INFO(Using)

include/mrdocs/Metadata/Info/Record.hpp

+10-5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <mrdocs/Metadata/Info.hpp>
1717
#include <mrdocs/Metadata/Source.hpp>
1818
#include <mrdocs/Metadata/Template.hpp>
19+
#include <mrdocs/Metadata/Info/Friend.hpp>
1920
#include <mrdocs/Dom.hpp>
2021
#include <mrdocs/Dom/LazyObject.hpp>
2122
#include <mrdocs/Dom/LazyArray.hpp>
@@ -46,7 +47,6 @@ struct RecordTranche
4647
std::vector<SymbolID> StaticVariables;
4748
std::vector<SymbolID> Concepts;
4849
std::vector<SymbolID> Guides;
49-
std::vector<SymbolID> Friends;
5050
std::vector<SymbolID> Usings;
5151
};
5252

@@ -60,7 +60,7 @@ allMembers(RecordTranche const& T)
6060
{
6161
// This is a trick to emulate views::concat in C++20
6262
return std::views::transform(
63-
std::views::iota(0, 12),
63+
std::views::iota(0, 11),
6464
[&T](int const i) -> auto const&
6565
{
6666
switch (i) {
@@ -74,8 +74,7 @@ allMembers(RecordTranche const& T)
7474
case 7: return T.StaticVariables;
7575
case 8: return T.Concepts;
7676
case 9: return T.Guides;
77-
case 10: return T.Friends;
78-
case 11: return T.Usings;
77+
case 10: return T.Usings;
7978
default: throw std::out_of_range("Invalid index");
8079
}
8180
}
@@ -102,7 +101,6 @@ tag_invoke(
102101
io.map("staticVariables", dom::LazyArray(I.StaticVariables, domCorpus));
103102
io.map("concepts", dom::LazyArray(I.Concepts, domCorpus));
104103
io.map("guides", dom::LazyArray(I.Guides, domCorpus));
105-
io.map("friends", dom::LazyArray(I.Friends, domCorpus));
106104
io.map("usings", dom::LazyArray(I.Usings, domCorpus));
107105
}
108106

@@ -295,8 +293,14 @@ struct RecordInfo final
295293
*/
296294
std::vector<SymbolID> Derived;
297295

296+
/** Lists of members.
297+
*/
298298
RecordInterface Interface;
299299

300+
/** List of friends.
301+
*/
302+
std::vector<FriendInfo> Friends;
303+
300304
//--------------------------------------------
301305

302306
explicit RecordInfo(SymbolID const& ID) noexcept
@@ -354,6 +358,7 @@ tag_invoke(
354358
io.map("derived", dom::LazyArray(I.Derived, domCorpus));
355359
io.map("interface", I.Interface);
356360
io.map("template", I.Template);
361+
io.map("friends", dom::LazyArray(I.Friends, domCorpus));
357362
}
358363

359364
/** Map the RecordInfo to a @ref dom::Value object.

mrdocs.rnc

-3
Original file line numberDiff line numberDiff line change
@@ -187,10 +187,7 @@ grammar
187187
Friend =
188188
element friend
189189
{
190-
Access ?,
191190
ID,
192-
Location *,
193-
Javadoc ?,
194191
(
195192
element befriended
196193
{

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

+23-4
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
{{! Base classes }}
3232
{{#if (any_of_by symbol.bases "isPublic")}}
3333
{{#> markup/dynamic-level-h }}Base Classes{{/markup/dynamic-level-h}}
34-
[,cols=2]
34+
[cols=2]
3535
|===
3636
| Name
3737
| Description
@@ -58,7 +58,7 @@
5858
{{#if symbol.constants}}
5959
{{#> markup/dynamic-level-h }}Members{{/markup/dynamic-level-h}}
6060

61-
[,cols=2]
61+
[cols=2]
6262
|===
6363
| Name
6464
| Description
@@ -73,6 +73,25 @@
7373
|===
7474

7575
{{/if}}
76+
{{/if}}
77+
{{! Friends }}
78+
{{#if symbol.friends}}
79+
{{#> markup/dynamic-level-h }}Friends{{/markup/dynamic-level-h}}
80+
[cols=2]
81+
|===
82+
| Name
83+
| Description
84+
{{#each symbol.friends }}
85+
{{#if symbol}}
86+
| {{#>markup/code}}{{> symbol/name symbol link=symbol }}{{/markup/code}}
87+
| {{> javadoc/inline-brief symbol.doc.brief }}
88+
{{else}}
89+
| {{#>markup/code}}{{> type/declarator type }}{{/markup/code}}
90+
|
91+
{{/if}}
92+
{{/each}}
93+
|===
94+
7695
{{/if}}
7796
{{! Using directives }}
7897
{{#if symbol.usingDirectives}}
@@ -82,7 +101,7 @@
82101
{{! Related symbols }}
83102
{{#if symbol.doc.related}}
84103
{{#> markup/dynamic-level-h }}Non-Member Functions{{/markup/dynamic-level-h}}
85-
[,cols=2]
104+
[cols=2]
86105
|===
87106
| Name
88107
| Description
@@ -96,7 +115,7 @@
96115
{{! Derived classes }}
97116
{{#if symbol.derived}}
98117
{{#> markup/dynamic-level-h }}Derived Classes{{/markup/dynamic-level-h}}
99-
[,cols=2]
118+
[cols=2]
100119
|===
101120
| Name
102121
| Description

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

-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
{{>symbol/members-table members=tranche.staticFunctions title=(concat (select label (concat label " ") "") "Static Member Functions")}}
3232
{{>symbol/members-table members=tranche.variables title=(concat (select label (concat label " ") "") "Data Members")}}
3333
{{>symbol/members-table members=tranche.staticVariables title=(concat (select label (concat label " ") "") "Static Data Members")}}
34-
{{>symbol/members-table members=tranche.friends title=(concat (select label (concat label " ") "") "Friends")}}
3534
{{>symbol/members-table members=tranche.aliases title=(concat (select label (concat label " ") "") "Aliases")}}
3635
{{>symbol/members-table members=tranche.usings title=(concat (select label (concat label " ") "") "Using Declarations")}}
3736
{{/if}}

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

+28
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,34 @@
9898
</table>
9999
</div>
100100
{{/if}}
101+
{{! Friends }}
102+
{{#if symbol.friends}}
103+
<div>
104+
{{#> markup/dynamic-level-h }}Friends{{/markup/dynamic-level-h}}
105+
<table>
106+
<thead>
107+
<tr>
108+
<th>Name</th>
109+
<th>Description</th>
110+
</tr>
111+
</thead>
112+
<tbody>
113+
{{#each symbol.friends }}
114+
<tr>
115+
{{#if symbol}}
116+
<td>{{#>markup/code}}{{> symbol/name symbol link=symbol }}{{/markup/code}}</td>
117+
<td>{{> javadoc/inline-brief symbol.doc.brief }}</td>
118+
{{else}}
119+
<td>{{#>markup/code}}{{> type/declarator type }}{{/markup/code}}</td>
120+
<td></td>
121+
{{/if}}
122+
</tr>
123+
{{/each}}
124+
|===
125+
</tbody>
126+
</table>
127+
</div>
128+
{{/if}}
101129
{{! Using directives }}
102130
{{#if symbol.usingDirectives}}
103131
<div>

src/lib/AST/ASTVisitor.cpp

+41-27
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,26 @@ populate(
713713
B.isVirtual());
714714
}
715715
}
716+
717+
// Iterate over the friends of the class
718+
if (D->hasDefinition() && D->hasFriends())
719+
{
720+
for (FriendDecl const* FD : D->friends())
721+
{
722+
// Check if the friend is a fundamental type
723+
// Declaring a fundamental type like `int` as a friend of a
724+
// class or struct does not have any practical effect. Thus,
725+
// it's not considered part of the public API.
726+
if (TypeSourceInfo const* TSI = FD->getFriendType())
727+
{
728+
Type const* T = TSI->getType().getTypePtrOrNull();
729+
MRDOCS_CHECK_OR_CONTINUE(!T || !T->isBuiltinType());
730+
}
731+
FriendInfo F;
732+
populate(F, FD);
733+
I.Friends.push_back(std::move(F));
734+
}
735+
}
716736
}
717737

718738
void
@@ -1113,32 +1133,31 @@ populate(
11131133
FriendInfo& I,
11141134
FriendDecl const* D)
11151135
{
1116-
// A NamedDecl nominated by a FriendDecl
1117-
// will be one of the following:
1118-
// - FunctionDecl
1119-
// - FunctionTemplateDecl
1120-
// - ClassTemplateDecl
1121-
if (NamedDecl* ND = D->getFriendDecl())
1136+
if (TypeSourceInfo const* TSI = D->getFriendType())
11221137
{
1123-
generateID(ND, I.FriendSymbol);
1124-
// If this is a friend function declaration naming
1125-
// a previously undeclared function, traverse it.
1126-
// in addition to this, traverse the declaration if
1127-
// it's a class templates first declared as a friend
1128-
if((ND->isFunctionOrFunctionTemplate() &&
1129-
ND->getFriendObjectKind() == Decl::FOK_Undeclared) ||
1130-
(isa<ClassTemplateDecl>(ND) && ND->isFirstDecl()))
1131-
{
1132-
traverse(cast<Decl>(ND));
1133-
}
1138+
I.Type = toTypeInfo(TSI->getType());
1139+
MRDOCS_CHECK_OR(I.Type->isNamed());
1140+
auto const& NTI = dynamic_cast<NamedTypeInfo&>(*I.Type);
1141+
MRDOCS_CHECK_OR(NTI.Name);
1142+
I.id = NTI.Name->id;
11341143
}
1135-
// Since a friend declaration which name non-class types
1136-
// will be ignored, a type nominated by a FriendDecl can
1137-
// essentially be anything
1138-
if (TypeSourceInfo const* TSI = D->getFriendType())
1144+
else if (NamedDecl const* ND = D->getFriendDecl())
11391145
{
1140-
I.FriendType = toTypeInfo(TSI->getType());
1146+
// ND can be a function or a class
1147+
ScopeExitRestore s(mode_, Dependency);
1148+
if (Info const* SI = traverse(dyn_cast<Decl>(ND)))
1149+
{
1150+
I.id = SI->id;
1151+
}
11411152
}
1153+
// The newly traversed info might need to inherit the
1154+
// documentation from the FriendDecl when the friend
1155+
// is the only declaration.
1156+
MRDOCS_CHECK_OR(isDocumented(D));
1157+
Info* TI = find(I.id);
1158+
MRDOCS_CHECK_OR(TI);
1159+
MRDOCS_CHECK_OR(!TI->javadoc);
1160+
populate(TI->javadoc, D);
11421161
}
11431162

11441163
void
@@ -1779,11 +1798,6 @@ addMember(RecordTranche& T, Info const& Member)
17791798
addMember(T.Guides, *U);
17801799
return;
17811800
}
1782-
if (auto const* U = Member.asFriendPtr())
1783-
{
1784-
addMember(T.Friends, *U);
1785-
return;
1786-
}
17871801
if (auto const* U = Member.asUsingPtr())
17881802
{
17891803
addMember(T.Usings, *U);

src/lib/AST/ASTVisitor.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,10 @@ class ASTVisitor
252252
*/
253253
TraversalMode mode_ = Regular;
254254

255+
/* A map which stores the Info types created by each decl.
256+
*/
257+
std::unordered_map<FriendDecl const*, Info const*> friendDecls_;
258+
255259
public:
256260
/** Constructor for ASTVisitor.
257261

src/lib/AST/ClangHelpers.hpp

-5
Original file line numberDiff line numberDiff line change
@@ -169,11 +169,6 @@ template <>
169169
struct InfoTypeFor<FieldDecl>
170170
: std::type_identity<VariableInfo> {};
171171

172-
// Extract FriendInfo from FriendDecl
173-
template <>
174-
struct InfoTypeFor<FriendDecl>
175-
: std::type_identity<FriendInfo> {};
176-
177172
// Extract GuideInfo from CXXDeductionGuideDecl
178173
template <>
179174
struct InfoTypeFor<CXXDeductionGuideDecl>

0 commit comments

Comments
 (0)