Skip to content

Commit 2b59269

Browse files
committed
feat: overload sets as shadow declarations
1 parent 069bd8f commit 2b59269

12 files changed

+389
-143
lines changed

src/lib/Metadata/Finalizers/OverloadsFinalizer.cpp

Lines changed: 203 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -13,97 +13,121 @@
1313

1414
namespace clang::mrdocs {
1515

16-
void
17-
OverloadsFinalizer::
18-
foldRecordMembers(std::vector<SymbolID> const& ids)
19-
{
20-
for (SymbolID const& id: ids)
21-
{
22-
Info* infoPtr = corpus_.find(id);
23-
MRDOCS_CHECK_OR_CONTINUE(infoPtr);
24-
MRDOCS_CHECK_OR_CONTINUE(infoPtr->isRecord());
25-
operator()(infoPtr->asRecord());
26-
}
27-
}
28-
29-
void
30-
OverloadsFinalizer::
31-
foldNamespaceMembers(std::vector<SymbolID> const& namespaceIds)
32-
{
33-
for (SymbolID const& namespaceId: namespaceIds)
34-
{
35-
Info* namespaceInfoPtr = corpus_.find(namespaceId);
36-
MRDOCS_CHECK_OR_CONTINUE(namespaceInfoPtr);
37-
MRDOCS_CHECK_OR_CONTINUE(namespaceInfoPtr->isNamespace());
38-
operator()(namespaceInfoPtr->asNamespace());
39-
}
40-
}
41-
4216
namespace {
4317
SymbolID
4418
findBaseClassPermutation(
4519
SymbolID const& contextId,
4620
CorpusImpl& corpus,
4721
ArrayRef<SymbolID> sameNameFunctionIds)
4822
{
23+
// Find the RecordInfo
4924
Info* info = corpus.find(contextId);
5025
MRDOCS_CHECK_OR(info, SymbolID::invalid);
51-
if (auto const* record = info->asRecordPtr())
26+
MRDOCS_CHECK_OR(info->isRecord(), SymbolID::invalid);
27+
for (auto const& base: info->asRecordPtr()->Bases)
5228
{
53-
for (auto const& base: record->Bases)
29+
// Find the i-th base class
30+
auto const baseInfo = corpus.find(base.Type->namedSymbol());
31+
MRDOCS_CHECK_OR_CONTINUE(baseInfo);
32+
auto const baseRecord = baseInfo->asRecordPtr();
33+
MRDOCS_CHECK_OR_CONTINUE(baseRecord);
34+
35+
// Iterate over all function tranches
36+
RecordTranche* tranchesPtrs[] = {
37+
&baseRecord->Interface.Public,
38+
&baseRecord->Interface.Protected,
39+
&baseRecord->Interface.Private,
40+
};
41+
for (RecordTranche* tranchePtr: tranchesPtrs)
5442
{
55-
auto const baseInfo = corpus.find(base.Type->namedSymbol());
56-
MRDOCS_CHECK_OR_CONTINUE(baseInfo);
57-
auto const baseRecord = baseInfo->asRecordPtr();
58-
MRDOCS_CHECK_OR_CONTINUE(baseRecord);
59-
RecordTranche* tranchesPtrs[] = {
60-
&baseRecord->Interface.Public,
61-
&baseRecord->Interface.Protected,
62-
&baseRecord->Interface.Private,
43+
std::vector<SymbolID>* trancheFunctionPtrs[] = {
44+
&tranchePtr->Functions,
45+
&tranchePtr->StaticFunctions
6346
};
64-
for (RecordTranche* tranchePtr: tranchesPtrs)
47+
for (std::vector<SymbolID>* trancheFunctionsPtr:
48+
trancheFunctionPtrs)
6549
{
66-
std::vector<SymbolID>* trancheFunctionPtrs[] = {
67-
&tranchePtr->Functions,
68-
&tranchePtr->StaticFunctions
69-
};
70-
for (std::vector<SymbolID>* trancheFunctionsPtr:
71-
trancheFunctionPtrs)
50+
// Find an overload set that's a permutation of the same
51+
// name functions
52+
for (SymbolID const& baseID: *trancheFunctionsPtr)
7253
{
73-
for (SymbolID const& baseID: *trancheFunctionsPtr)
74-
{
75-
Info* baseFuncMember = corpus.find(baseID);
76-
MRDOCS_CHECK_OR_CONTINUE(baseFuncMember);
77-
MRDOCS_CHECK_OR_CONTINUE(baseFuncMember->isOverloads());
78-
auto* overloads = baseFuncMember->asOverloadsPtr();
79-
MRDOCS_CHECK_OR_CONTINUE(overloads);
80-
// Does this overload set have the same functions
81-
MRDOCS_CHECK_OR_CONTINUE(
82-
std::ranges::is_permutation(
83-
overloads->Members,
84-
sameNameFunctionIds));
85-
return overloads->id;
86-
}
54+
Info* baseFuncMember = corpus.find(baseID);
55+
MRDOCS_CHECK_OR_CONTINUE(baseFuncMember);
56+
MRDOCS_CHECK_OR_CONTINUE(baseFuncMember->isOverloads());
57+
auto* overloads = baseFuncMember->asOverloadsPtr();
58+
MRDOCS_CHECK_OR_CONTINUE(overloads);
59+
// Does this overload set have the same functions
60+
MRDOCS_CHECK_OR_CONTINUE(
61+
std::ranges::is_permutation(
62+
overloads->Members,
63+
sameNameFunctionIds));
64+
return overloads->id;
8765
}
8866
}
8967
}
9068
}
9169
return SymbolID::invalid;
9270
}
71+
72+
SymbolID
73+
findIntroducedNamespacePermutation(
74+
SymbolID const& contextId,
75+
CorpusImpl& corpus,
76+
ArrayRef<SymbolID> sameNameFunctionIds)
77+
{
78+
// Find the UsingInfo
79+
Info* info = corpus.find(contextId);
80+
MRDOCS_CHECK_OR(info, SymbolID::invalid);
81+
MRDOCS_CHECK_OR(info->isUsing(), SymbolID::invalid);
82+
83+
// Find the FunctionInfo for the first shadow declaration
84+
MRDOCS_CHECK_OR(!sameNameFunctionIds.empty(), SymbolID::invalid);
85+
Info* firstShadowInfo = corpus.find(sameNameFunctionIds.front());
86+
MRDOCS_CHECK_OR(firstShadowInfo, SymbolID::invalid);
87+
MRDOCS_CHECK_OR(firstShadowInfo->isFunction(), SymbolID::invalid);
88+
auto* firstShadowFunction = firstShadowInfo->asFunctionPtr();
89+
90+
// Find the introduced namespace of the first shadow declaration
91+
MRDOCS_CHECK_OR(firstShadowFunction->Parent, SymbolID::invalid);
92+
Info* parentInfo = corpus.find(firstShadowFunction->Parent);
93+
MRDOCS_CHECK_OR(parentInfo, SymbolID::invalid);
94+
MRDOCS_CHECK_OR(parentInfo->isNamespace(), SymbolID::invalid);
95+
auto* parentNamespace = parentInfo->asNamespacePtr();
96+
97+
// Find an overload set that's a permutation of the same name functions
98+
for (SymbolID const& baseID: parentNamespace->Members.Functions)
99+
{
100+
Info* baseFuncMember = corpus.find(baseID);
101+
MRDOCS_CHECK_OR_CONTINUE(baseFuncMember);
102+
MRDOCS_CHECK_OR_CONTINUE(baseFuncMember->isOverloads());
103+
auto* overloads = baseFuncMember->asOverloadsPtr();
104+
MRDOCS_CHECK_OR_CONTINUE(overloads);
105+
// Does this overload set have the same functions
106+
MRDOCS_CHECK_OR_CONTINUE(
107+
std::ranges::is_permutation(
108+
overloads->Members,
109+
sameNameFunctionIds));
110+
return overloads->id;
111+
}
112+
return SymbolID::invalid;
113+
}
93114
}
94115

95116
void
96117
OverloadsFinalizer::
97118
foldOverloads(SymbolID const& contextId, std::vector<SymbolID>& functionIds, bool isStatic)
98119
{
120+
Info* contextInfo = corpus_.find(contextId);
121+
MRDOCS_CHECK_OR(contextInfo);
122+
99123
for (auto functionIdIt = functionIds.begin();
100124
functionIdIt != functionIds.end();
101125
++functionIdIt)
102126
{
103127
// Get the FunctionInfo for the current id
104-
auto recordInfoPtr = corpus_.find(*functionIdIt);
105-
MRDOCS_CHECK_OR_CONTINUE(recordInfoPtr);
106-
auto* function = recordInfoPtr->asFunctionPtr();
128+
auto infoPtr = corpus_.find(*functionIdIt);
129+
MRDOCS_CHECK_OR_CONTINUE(infoPtr);
130+
auto* function = infoPtr->asFunctionPtr();
107131
MRDOCS_CHECK_OR_CONTINUE(function);
108132
MRDOCS_CHECK_OR_CONTINUE(function->Class != FunctionClass::Destructor);
109133

@@ -133,23 +157,56 @@ foldOverloads(SymbolID const& contextId, std::vector<SymbolID>& functionIds, boo
133157
// Check if any of the base classes has an overload set
134158
// with the exact same function ids. If that's the case,
135159
// the function will create a reference.
136-
SymbolID equivalentOverloadsID = findBaseClassPermutation(
137-
contextId, corpus_, sameNameFunctionIds);
138-
if (equivalentOverloadsID)
160+
if (contextInfo->isRecord())
139161
{
140-
MRDOCS_ASSERT(corpus_.find(equivalentOverloadsID));
141-
// This base overload set becomes the
142-
// representation in the record
143-
*functionIdIt = equivalentOverloadsID;
144-
auto const offset = functionIdIt - functionIds.begin();
145-
// Erase the other function ids with
146-
// the same name
147-
for (SymbolID sameNameId: sameNameFunctionIds)
162+
SymbolID equivalentOverloadsID = findBaseClassPermutation(
163+
contextId,
164+
corpus_,
165+
sameNameFunctionIds);
166+
if (equivalentOverloadsID)
148167
{
149-
std::erase(functionIds, sameNameId);
168+
MRDOCS_ASSERT(corpus_.find(equivalentOverloadsID));
169+
// This base overload set becomes the
170+
// representation in the record
171+
*functionIdIt = equivalentOverloadsID;
172+
auto const offset = functionIdIt - functionIds.begin();
173+
// Erase the other function ids with
174+
// the same name
175+
for (SymbolID sameNameId: sameNameFunctionIds)
176+
{
177+
std::erase(functionIds, sameNameId);
178+
}
179+
functionIdIt = functionIds.begin() + offset;
180+
continue;
181+
}
182+
}
183+
184+
// Check if the namespace of the name introduced in the
185+
// using declaration has an overload set with the
186+
// exact same function ids. If that's the case,
187+
// the function will create a reference.
188+
if (contextInfo->isUsing())
189+
{
190+
SymbolID introducedOverloadsID = findIntroducedNamespacePermutation(
191+
contextId,
192+
corpus_,
193+
sameNameFunctionIds);
194+
if (introducedOverloadsID)
195+
{
196+
MRDOCS_ASSERT(corpus_.find(introducedOverloadsID));
197+
// This base overload set becomes the
198+
// representation in the record
199+
*functionIdIt = introducedOverloadsID;
200+
auto const offset = functionIdIt - functionIds.begin();
201+
// Erase the other function ids with
202+
// the same name
203+
for (SymbolID sameNameId: sameNameFunctionIds)
204+
{
205+
std::erase(functionIds, sameNameId);
206+
}
207+
functionIdIt = functionIds.begin() + offset;
208+
continue;
150209
}
151-
functionIdIt = functionIds.begin() + offset;
152-
continue;
153210
}
154211

155212
// FunctionInfo is not unique and there's no equivalent
@@ -176,13 +233,50 @@ foldOverloads(SymbolID const& contextId, std::vector<SymbolID>& functionIds, boo
176233
}
177234
}
178235

236+
namespace {
237+
template <class T>
238+
constexpr
239+
auto
240+
toDerivedView(std::vector<SymbolID> const& ids, CorpusImpl& c)
241+
{
242+
return ids |
243+
std::views::transform([&c](SymbolID const& id) {
244+
return c.find(id);
245+
}) |
246+
std::views::filter([](Info* infoPtr) {
247+
return infoPtr != nullptr;
248+
}) |
249+
std::views::transform([](Info* infoPtr) -> T* {
250+
return dynamic_cast<T*>(infoPtr);
251+
}) |
252+
std::views::filter([](T* ptr) {
253+
return ptr != nullptr;
254+
}) |
255+
std::views::transform([](T* ptr) -> T& {
256+
return *ptr;
257+
});
258+
}
259+
}
260+
179261
void
180262
OverloadsFinalizer::
181263
operator()(NamespaceInfo& I)
182264
{
265+
MRDOCS_CHECK_OR(!finalized_.contains(I.id));
183266
foldOverloads(I.id, I.Members.Functions, true);
184-
foldRecordMembers(I.Members.Records);
185-
foldNamespaceMembers(I.Members.Namespaces);
267+
for (RecordInfo& RI: toDerivedView<RecordInfo>(I.Members.Records, corpus_))
268+
{
269+
operator()(RI);
270+
}
271+
for (NamespaceInfo& NI: toDerivedView<NamespaceInfo>(I.Members.Namespaces, corpus_))
272+
{
273+
operator()(NI);
274+
}
275+
for (UsingInfo& UI: toDerivedView<UsingInfo>(I.Members.Usings, corpus_))
276+
{
277+
operator()(UI);
278+
}
279+
finalized_.emplace(I.id);
186280
}
187281

188282
void
@@ -211,9 +305,39 @@ operator()(RecordInfo& I)
211305
foldOverloads(I.id, I.Interface.Public.StaticFunctions, true);
212306
foldOverloads(I.id, I.Interface.Protected.StaticFunctions, true);
213307
foldOverloads(I.id, I.Interface.Private.StaticFunctions, true);
214-
foldRecordMembers(I.Interface.Public.Records);
215-
foldRecordMembers(I.Interface.Protected.Records);
216-
foldRecordMembers(I.Interface.Private.Records);
308+
for (RecordInfo& RI: toDerivedView<RecordInfo>(I.Interface.Public.Records, corpus_)) {
309+
operator()(RI);
310+
}
311+
for (RecordInfo& RI: toDerivedView<RecordInfo>(I.Interface.Protected.Records, corpus_)) {
312+
operator()(RI);
313+
}
314+
for (RecordInfo& RI: toDerivedView<RecordInfo>(I.Interface.Private.Records, corpus_)) {
315+
operator()(RI);
316+
}
317+
finalized_.emplace(I.id);
318+
}
319+
320+
void
321+
OverloadsFinalizer::
322+
operator()(UsingInfo& I)
323+
{
324+
MRDOCS_CHECK_OR(!finalized_.contains(I.id));
325+
auto shadowFunctions = toDerivedView<FunctionInfo>(I.ShadowDeclarations, corpus_);
326+
for (FunctionInfo& FI: shadowFunctions)
327+
{
328+
Info* PI = corpus_.find(FI.Parent);
329+
MRDOCS_CHECK_OR_CONTINUE(PI);
330+
if (auto* NI = PI->asNamespacePtr())
331+
{
332+
operator()(*NI);
333+
}
334+
else if (auto* RI = PI->asRecordPtr())
335+
{
336+
operator()(*RI);
337+
}
338+
break;
339+
}
340+
foldOverloads(I.id, I.ShadowDeclarations, true);
217341
finalized_.emplace(I.id);
218342
}
219343

src/lib/Metadata/Finalizers/OverloadsFinalizer.hpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,6 @@ class OverloadsFinalizer
2929
CorpusImpl& corpus_;
3030
std::set<SymbolID> finalized_;
3131

32-
void
33-
foldRecordMembers(std::vector<SymbolID> const& ids);
34-
35-
void
36-
foldNamespaceMembers(std::vector<SymbolID> const& namespaceIds);
37-
3832
void
3933
foldOverloads(
4034
SymbolID const& contextId,
@@ -55,12 +49,23 @@ class OverloadsFinalizer
5549
operator()(globalPtr->asNamespace());
5650
}
5751

52+
/* Visit the namespace members identifying overload sets
53+
*/
5854
void
5955
operator()(NamespaceInfo& I);
6056

57+
/* Visit the record members identifying overload sets
58+
*/
6159
void
6260
operator()(RecordInfo& I);
6361

62+
/* Visit the using directive shadows for overloads
63+
*/
64+
void
65+
operator()(UsingInfo& I);
66+
67+
/* No-op for other Info types
68+
*/
6469
void
6570
operator()(Info&) {}
6671
};

0 commit comments

Comments
 (0)