Skip to content

Commit bcae45a

Browse files
committed
overloads
1 parent 20eac81 commit bcae45a

File tree

9 files changed

+255
-214
lines changed

9 files changed

+255
-214
lines changed

include/mrdocs/Metadata/Info/Overloads.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ struct OverloadsInfo final
3434
/// Info about the return type of this function.
3535
Polymorphic<TypeInfo> ReturnType = std::nullopt;
3636

37+
StorageClassKind StorageClass = StorageClassKind::None;
38+
3739
//--------------------------------------------
3840

3941
explicit OverloadsInfo(SymbolID const& ID) noexcept

src/lib/CorpusImpl.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,17 +1019,17 @@ CorpusImpl::finalize()
10191019
finalizer.build();
10201020
}
10211021

1022-
// Finalizing record interfaces
1022+
if (config->overloads)
10231023
{
1024-
report::debug(" - Finalizing records");
1025-
RecordsFinalizer finalizer(*this);
1024+
report::debug(" - Finalizing overloads");
1025+
OverloadsFinalizer finalizer(*this);
10261026
finalizer.build();
10271027
}
10281028

1029-
if (config->overloads)
1029+
// Finalizing record interfaces
10301030
{
1031-
report::debug(" - Finalizing overloads");
1032-
OverloadsFinalizer finalizer(*this);
1031+
report::debug(" - Finalizing records");
1032+
RecordsFinalizer finalizer(*this);
10331033
finalizer.build();
10341034
}
10351035

src/lib/Metadata/Finalizers/OverloadsFinalizer.cpp

Lines changed: 160 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -32,38 +32,24 @@ findBaseClassPermutation(
3232
auto const baseRecord = baseInfo->asRecordPtr();
3333
MRDOCS_CHECK_OR_CONTINUE(baseRecord);
3434

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)
35+
// Find an overload set that's a permutation of the same
36+
// name functions
37+
for (auto const& baseMember: baseRecord->Members)
4238
{
43-
std::vector<SymbolID>* trancheFunctionPtrs[] = {
44-
&tranchePtr->Functions,
45-
&tranchePtr->StaticFunctions
46-
};
47-
for (std::vector<SymbolID>* trancheFunctionsPtr:
48-
trancheFunctionPtrs)
49-
{
50-
// Find an overload set that's a permutation of the same
51-
// name functions
52-
for (SymbolID const& baseID: *trancheFunctionsPtr)
53-
{
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;
65-
}
66-
}
39+
MRDOCS_CHECK_OR_CONTINUE(baseMember.Kind == InfoKind::Function);
40+
41+
SymbolID const& baseID = baseMember.id;
42+
Info* baseFuncMember = corpus.find(baseID);
43+
MRDOCS_CHECK_OR_CONTINUE(baseFuncMember);
44+
MRDOCS_CHECK_OR_CONTINUE(baseFuncMember->isOverloads());
45+
auto* overloads = baseFuncMember->asOverloadsPtr();
46+
MRDOCS_CHECK_OR_CONTINUE(overloads);
47+
// Does this overload set have the same functions
48+
MRDOCS_CHECK_OR_CONTINUE(
49+
std::ranges::is_permutation(
50+
overloads->Members,
51+
sameNameFunctionIds));
52+
return overloads->id;
6753
}
6854
}
6955
return SymbolID::invalid;
@@ -115,7 +101,7 @@ findIntroducedNamespacePermutation(
115101

116102
void
117103
OverloadsFinalizer::
118-
foldOverloads(SymbolID const& contextId, std::vector<SymbolID>& functionIds, bool isStatic)
104+
foldOverloads(SymbolID const& contextId, std::vector<SymbolID>& functionIds, AccessKind access, bool isStatic)
119105
{
120106
Info* contextInfo = corpus_.find(contextId);
121107
MRDOCS_CHECK_OR(contextInfo);
@@ -232,11 +218,144 @@ foldOverloads(SymbolID const& contextId, std::vector<SymbolID>& functionIds, boo
232218
}
233219
}
234220

221+
// FIXME: dedup with above
222+
void
223+
OverloadsFinalizer::
224+
foldOverloads(SymbolID const& contextId, std::vector<MemberInfo>& members)
225+
{
226+
Info* contextInfo = corpus_.find(contextId);
227+
MRDOCS_CHECK_OR(contextInfo);
228+
229+
for (auto memberIt = members.begin();
230+
memberIt != members.end();
231+
++memberIt)
232+
{
233+
MRDOCS_CHECK_OR_CONTINUE(memberIt->Kind == InfoKind::Function);
234+
235+
// Get the FunctionInfo for the current id
236+
auto infoPtr = corpus_.find(memberIt->id);
237+
MRDOCS_CHECK_OR_CONTINUE(infoPtr);
238+
auto* function = infoPtr->asFunctionPtr();
239+
MRDOCS_CHECK_OR_CONTINUE(function);
240+
241+
AccessKind const access = function->Access;
242+
bool const isStatic = (function->StorageClass == StorageClassKind::Static);
243+
244+
// Check if the FunctionInfo is unique
245+
std::ranges::subrange otherMembers(
246+
std::next(memberIt),
247+
members.end());
248+
auto isSameNameFunction = [&](MemberInfo const& other) {
249+
MRDOCS_CHECK_OR(other.EffectiveAccess == access, false);
250+
MRDOCS_CHECK_OR(other.Kind == InfoKind::Function, false);
251+
SymbolID const& otherID = other.id;
252+
auto const otherFunctionPtr = corpus_.find(otherID);
253+
MRDOCS_CHECK_OR(otherFunctionPtr, false);
254+
FunctionInfo const& otherInfo = otherFunctionPtr->asFunction();
255+
return function->Name == otherInfo.Name && (isStatic == (otherInfo.StorageClass == StorageClassKind::Static)) ;
256+
};
257+
auto sameNameIt = std::ranges::
258+
find_if(otherMembers, isSameNameFunction);
259+
bool const isUniqueFunction = sameNameIt == otherMembers.end();
260+
MRDOCS_CHECK_OR_CONTINUE(!isUniqueFunction);
261+
262+
// Create a list of FunctionInfo overloads
263+
auto sameNameMembersView =
264+
std::ranges::subrange(memberIt, members.end()) |
265+
std::views::filter(isSameNameFunction) |
266+
std::views::transform(&MemberInfo::id);
267+
SmallVector<SymbolID, 16> sameNameMembers(
268+
sameNameMembersView.begin(),
269+
sameNameMembersView.end());
270+
271+
// Check if any of the base classes has an overload set
272+
// with the exact same function ids. If that's the case,
273+
// the function will create a reference.
274+
if (contextInfo->isRecord())
275+
{
276+
SymbolID equivalentOverloadsID = findBaseClassPermutation(
277+
contextId,
278+
corpus_,
279+
sameNameMembers);
280+
if (equivalentOverloadsID)
281+
{
282+
MRDOCS_ASSERT(corpus_.find(equivalentOverloadsID));
283+
// This base overload set becomes the
284+
// representation in the record
285+
memberIt->id = equivalentOverloadsID;
286+
auto const offset = memberIt - members.begin();
287+
// Erase the other function ids with
288+
// the same name
289+
for (SymbolID sameNameId: sameNameMembers)
290+
{
291+
std::erase_if(members, [&](MemberInfo const& member) { return member.id == sameNameId; });
292+
}
293+
memberIt = members.begin() + offset;
294+
continue;
295+
}
296+
}
297+
298+
// Check if the namespace of the name introduced in the
299+
// using declaration has an overload set with the
300+
// exact same function ids. If that's the case,
301+
// the function will create a reference.
302+
if (contextInfo->isUsing())
303+
{
304+
SymbolID introducedOverloadsID = findIntroducedNamespacePermutation(
305+
contextId,
306+
corpus_,
307+
sameNameMembers);
308+
if (introducedOverloadsID)
309+
{
310+
MRDOCS_ASSERT(corpus_.find(introducedOverloadsID));
311+
// This base overload set becomes the
312+
// representation in the record
313+
memberIt->id = introducedOverloadsID;
314+
auto const offset = memberIt - members.begin();
315+
// Erase the other function ids with
316+
// the same name
317+
for (SymbolID sameNameId: sameNameMembers)
318+
{
319+
std::erase_if(members, [&](MemberInfo const& member) { return member.id == sameNameId; });
320+
}
321+
memberIt = members.begin() + offset;
322+
continue;
323+
}
324+
}
325+
326+
// FunctionInfo is not unique and there's no equivalent
327+
// overload set in base classes, so we merge it with the
328+
// other FunctionInfos into a new OverloadsInfo
329+
OverloadsInfo O(contextId, function->Name, access, isStatic);
330+
addMember(O, *function);
331+
memberIt->id = O.id;
332+
auto const itOffset = memberIt - members.begin();
333+
for (auto otherIt = memberIt + 1; otherIt != members.end(); ++otherIt)
334+
{
335+
MRDOCS_CHECK_OR_CONTINUE(otherIt->EffectiveAccess == access);
336+
MRDOCS_CHECK_OR_CONTINUE(otherIt->Kind == InfoKind::Function);
337+
338+
Info* otherInfoPtr = corpus_.find(otherIt->id);
339+
MRDOCS_CHECK_OR_CONTINUE(otherInfoPtr);
340+
auto* otherFunction = otherInfoPtr->asFunctionPtr();
341+
MRDOCS_CHECK_OR_CONTINUE(otherFunction);
342+
MRDOCS_CHECK_OR_CONTINUE(isStatic == (otherFunction->StorageClass == StorageClassKind::Static));
343+
if (function->Name == otherFunction->Name)
344+
{
345+
addMember(O, *otherFunction);
346+
otherIt = std::prev(members.erase(otherIt));
347+
}
348+
}
349+
memberIt = members.begin() + itOffset;
350+
MRDOCS_ASSERT(corpus_.info_.emplace(std::make_unique<OverloadsInfo>(std::move(O))).second);
351+
}
352+
}
353+
235354
namespace {
236-
template <class T>
355+
template <class T, range_of<SymbolID> R>
237356
constexpr
238357
auto
239-
toDerivedView(std::vector<SymbolID> const& ids, CorpusImpl& c)
358+
toDerivedView(R&& ids, CorpusImpl& c)
240359
{
241360
return ids |
242361
std::views::transform([&c](SymbolID const& id) {
@@ -264,7 +383,7 @@ operator()(NamespaceInfo& I)
264383
MRDOCS_CHECK_OR(!finalized_.contains(I.id));
265384
finalized_.emplace(I.id);
266385

267-
foldOverloads(I.id, I.Members.Functions, true);
386+
foldOverloads(I.id, I.Members.Functions, AccessKind::None, true);
268387
for (RecordInfo& RI: toDerivedView<RecordInfo>(I.Members.Records, corpus_))
269388
{
270389
operator()(RI);
@@ -301,19 +420,11 @@ operator()(RecordInfo& I)
301420
MRDOCS_CHECK_OR(baseRecord);
302421
operator()(*baseRecord);
303422
}
304-
foldOverloads(I.id, I.Interface.Public.Functions, false);
305-
foldOverloads(I.id, I.Interface.Protected.Functions, false);
306-
foldOverloads(I.id, I.Interface.Private.Functions, false);
307-
foldOverloads(I.id, I.Interface.Public.StaticFunctions, true);
308-
foldOverloads(I.id, I.Interface.Protected.StaticFunctions, true);
309-
foldOverloads(I.id, I.Interface.Private.StaticFunctions, true);
310-
for (RecordInfo& RI: toDerivedView<RecordInfo>(I.Interface.Public.Records, corpus_)) {
311-
operator()(RI);
312-
}
313-
for (RecordInfo& RI: toDerivedView<RecordInfo>(I.Interface.Protected.Records, corpus_)) {
314-
operator()(RI);
315-
}
316-
for (RecordInfo& RI: toDerivedView<RecordInfo>(I.Interface.Private.Records, corpus_)) {
423+
424+
foldOverloads(I.id, I.Members);
425+
426+
auto&& memberIds = std::ranges::views::transform(I.Members, &MemberInfo::id);
427+
for (RecordInfo& RI: toDerivedView<RecordInfo>(memberIds, corpus_)) {
317428
operator()(RI);
318429
}
319430
}
@@ -340,7 +451,7 @@ operator()(UsingInfo& I)
340451
}
341452
break;
342453
}
343-
foldOverloads(I.id, I.ShadowDeclarations, true);
454+
foldOverloads(I.id, I.ShadowDeclarations, AccessKind::None, true);
344455
}
345456

346457
} // clang::mrdocs

src/lib/Metadata/Finalizers/OverloadsFinalizer.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,14 @@ class OverloadsFinalizer
3333
foldOverloads(
3434
SymbolID const& contextId,
3535
std::vector<SymbolID>& functionIds,
36+
AccessKind access,
3637
bool isStatic);
3738

39+
void
40+
foldOverloads(
41+
SymbolID const& contextId,
42+
std::vector<MemberInfo>& members);
43+
3844
public:
3945
OverloadsFinalizer(CorpusImpl& corpus)
4046
: corpus_(corpus)

src/lib/Metadata/Finalizers/RecordsFinalizer.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,14 @@ addMember(RecordTranche& T, Info const& Member)
8989
}
9090
if (auto const* U = Member.asOverloadsPtr())
9191
{
92-
addMember(T.Functions, *U);
92+
if (U->StorageClass != StorageClassKind::Static)
93+
{
94+
addMember(T.Functions, *U);
95+
}
96+
else
97+
{
98+
addMember(T.StaticFunctions, *U);
99+
}
93100
return;
94101
}
95102
report::error("Cannot push {} of type {} into tranche",

src/lib/Metadata/Info/Overloads.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ OverloadsInfo::OverloadsInfo(SymbolID const &Parent, std::string_view Name,
2626
: InfoCommonBase(SymbolID::createFromString(std::format(
2727
"{}-{}-{}-{}", toBase16(Parent), Name, toString(access), isStatic))) {
2828
this->Parent = Parent;
29+
if (isStatic) this->StorageClass = StorageClassKind::Static;
2930
}
3031

3132
void

0 commit comments

Comments
 (0)