Skip to content

Commit 4550326

Browse files
committed
inherit base class overload sets
#feat
1 parent d6b2970 commit 4550326

File tree

9 files changed

+631
-50
lines changed

9 files changed

+631
-50
lines changed

include/mrdocs/Support/Algorithm.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ contains_n_any(Range const& range, std::initializer_list<El> const& els, std::si
163163
}
164164

165165
/** Find the last element in a range that matches an element in the specified range.
166+
166167
@param range The range to search.
167168
@param els The elements to search for.
168169
@return An iterator to the last element found, or std::ranges::end(range) if not found.

src/lib/Gen/hbs/SinglePageVisitor.cpp

+11-12
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,17 @@ operator()(T const& I)
2525
{
2626
ex_.async([this, &I, symbolIdx = numSymbols_++](Builder& builder)
2727
{
28-
29-
// Output to an independent string first (async), then write to
30-
// the shared stream (sync)
31-
std::stringstream ss;
32-
if(auto r = builder(ss, I))
33-
{
34-
writePage(ss.str(), symbolIdx);
35-
}
36-
else
37-
{
38-
r.error().Throw();
39-
}
28+
// Output to an independent string first (async), then write to
29+
// the shared stream (sync)
30+
std::stringstream ss;
31+
if(auto r = builder(ss, I))
32+
{
33+
writePage(ss.str(), symbolIdx);
34+
}
35+
else
36+
{
37+
r.error().Throw();
38+
}
4039
});
4140
}
4241
Corpus::TraverseOptions opts = {.skipInherited = std::same_as<T, RecordInfo>};

src/lib/Metadata/Finalizers/NamespacesFinalizer.hpp

+4-6
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,11 @@
1616

1717
namespace clang::mrdocs {
1818

19-
/** Finalizes a set of Info.
19+
/** Finalizes the namespaces in corpus.
2020
21-
This removes any references to SymbolIDs
22-
which do not exist.
23-
24-
References which should always be valid
25-
are not checked.
21+
Namespaces might be removed or have
22+
their extraction mode updated depending
23+
on its members.
2624
*/
2725
class NamespacesFinalizer
2826
{

src/lib/Metadata/Finalizers/OverloadsFinalizer.cpp

+132-30
Original file line numberDiff line numberDiff line change
@@ -28,54 +28,139 @@ foldRecordMembers(std::vector<SymbolID> const& ids)
2828

2929
void
3030
OverloadsFinalizer::
31-
foldNamespaceMembers(std::vector<SymbolID> const& ids)
31+
foldNamespaceMembers(std::vector<SymbolID> const& namespaceIds)
3232
{
33-
for (SymbolID const& id: ids)
33+
for (SymbolID const& namespaceId: namespaceIds)
3434
{
35-
Info* infoPtr = corpus_.find(id);
36-
MRDOCS_CHECK_OR_CONTINUE(infoPtr);
37-
auto* ns = dynamic_cast<NamespaceInfo*>(infoPtr);
35+
Info* namespaceInfoPtr = corpus_.find(namespaceId);
36+
MRDOCS_CHECK_OR_CONTINUE(namespaceInfoPtr);
37+
auto* ns = dynamic_cast<NamespaceInfo*>(namespaceInfoPtr);
3838
MRDOCS_CHECK_OR_CONTINUE(ns);
3939
operator()(*ns);
4040
}
4141
}
4242

43+
namespace {
44+
SymbolID
45+
findBaseClassPermutation(
46+
SymbolID const& contextId,
47+
CorpusImpl& corpus,
48+
ArrayRef<SymbolID> sameNameFunctionIds)
49+
{
50+
Info* info = corpus.find(contextId);
51+
MRDOCS_CHECK_OR(info, SymbolID::invalid);
52+
if (auto* record = dynamic_cast<RecordInfo*>(info))
53+
{
54+
bool overloadsFromBase = false;
55+
for (auto const& base: record->Bases)
56+
{
57+
auto const baseInfo = corpus.find(base.Type->namedSymbol());
58+
MRDOCS_CHECK_OR_CONTINUE(baseInfo);
59+
auto const baseRecord = dynamic_cast<RecordInfo*>(baseInfo);
60+
MRDOCS_CHECK_OR_CONTINUE(baseRecord);
61+
RecordTranche* tranchesPtrs[] = {
62+
&baseRecord->Interface.Public,
63+
&baseRecord->Interface.Protected,
64+
&baseRecord->Interface.Private,
65+
};
66+
for (RecordTranche* tranchePtr: tranchesPtrs)
67+
{
68+
std::vector<SymbolID>* trancheFunctionPtrs[] = {
69+
&tranchePtr->Functions,
70+
&tranchePtr->StaticFunctions
71+
};
72+
for (std::vector<SymbolID>* trancheFunctionsPtr:
73+
trancheFunctionPtrs)
74+
{
75+
for (SymbolID const& baseID: *trancheFunctionsPtr)
76+
{
77+
Info* baseFuncMember = corpus.find(baseID);
78+
MRDOCS_CHECK_OR_CONTINUE(baseFuncMember);
79+
MRDOCS_CHECK_OR_CONTINUE(baseFuncMember->isOverloads());
80+
auto* overloads = dynamic_cast<OverloadsInfo*>(baseFuncMember);
81+
MRDOCS_CHECK_OR_CONTINUE(overloads);
82+
// Does this overload set have the same functions
83+
MRDOCS_CHECK_OR_CONTINUE(
84+
std::ranges::is_permutation(
85+
overloads->Members,
86+
sameNameFunctionIds));
87+
return overloads->id;
88+
}
89+
}
90+
}
91+
}
92+
}
93+
return SymbolID::invalid;
94+
}
95+
}
96+
4397
void
4498
OverloadsFinalizer::
45-
foldOverloads(SymbolID const& parent, std::vector<SymbolID>& ids)
99+
foldOverloads(SymbolID const& contextId, std::vector<SymbolID>& functionIds)
46100
{
47-
for (auto it = ids.begin(); it != ids.end(); ++it)
101+
for (auto functionIdIt = functionIds.begin();
102+
functionIdIt != functionIds.end();
103+
++functionIdIt)
48104
{
49105
// Get the FunctionInfo for the current id
50-
auto infoPtr = corpus_.find(*it);
51-
MRDOCS_CHECK_OR_CONTINUE(infoPtr);
52-
auto* function = dynamic_cast<FunctionInfo*>(infoPtr);
106+
auto recordInfoPtr = corpus_.find(*functionIdIt);
107+
MRDOCS_CHECK_OR_CONTINUE(recordInfoPtr);
108+
auto* function = dynamic_cast<FunctionInfo*>(recordInfoPtr);
53109
MRDOCS_CHECK_OR_CONTINUE(function);
54110

55111
// Check if the FunctionInfo is unique
56-
auto sameNameIt =
57-
std::find_if(
58-
it + 1,
59-
ids.end(),
60-
[&](SymbolID const& otherID)
61-
{
62-
auto const otherInfoPtr = corpus_.find(otherID);
63-
MRDOCS_CHECK_OR(otherInfoPtr, false);
64-
Info& otherInfo = *otherInfoPtr;
65-
return function->Name == otherInfo.Name;
66-
});
67-
if (sameNameIt == ids.end())
112+
std::ranges::subrange otherFunctionIds(
113+
std::next(functionIdIt),
114+
functionIds.end());
115+
auto isSameNameFunction = [&](SymbolID const& otherID) {
116+
auto const otherFunctionPtr = corpus_.find(otherID);
117+
MRDOCS_CHECK_OR(otherFunctionPtr, false);
118+
Info const& otherInfo = *otherFunctionPtr;
119+
return function->Name == otherInfo.Name;
120+
};
121+
auto sameNameIt = std::ranges::
122+
find_if(otherFunctionIds, isSameNameFunction);
123+
bool const isUniqueFunction = sameNameIt == otherFunctionIds.end();
124+
MRDOCS_CHECK_OR_CONTINUE(!isUniqueFunction);
125+
126+
// Create a list of FunctionInfo overloads
127+
auto sameNameFunctionIdsView =
128+
std::ranges::subrange(functionIdIt, functionIds.end()) |
129+
std::views::filter(isSameNameFunction);
130+
SmallVector<SymbolID, 16> sameNameFunctionIds(
131+
sameNameFunctionIdsView.begin(),
132+
sameNameFunctionIdsView.end());
133+
134+
// Check if any of the base classes has an overload set
135+
// with the exact same function ids. If that's the case,
136+
// the function will create a reference.
137+
SymbolID equivalentOverloadsID = findBaseClassPermutation(
138+
contextId, corpus_, sameNameFunctionIds);
139+
if (equivalentOverloadsID)
68140
{
141+
MRDOCS_ASSERT(corpus_.find(equivalentOverloadsID));
142+
// This base overload set becomes the
143+
// representation in the record
144+
*functionIdIt = equivalentOverloadsID;
145+
auto const offset = functionIdIt - functionIds.begin();
146+
// Erase the other function ids with
147+
// the same name
148+
for (SymbolID sameNameId: sameNameFunctionIds)
149+
{
150+
std::erase(functionIds, sameNameId);
151+
}
152+
functionIdIt = functionIds.begin() + offset;
69153
continue;
70154
}
71155

72-
// FunctionInfo is not unique, so merge it with the other FunctionInfos
73-
// into an OverloadsInfo
74-
OverloadsInfo O(parent, function->Name);
156+
// FunctionInfo is not unique and there's no equivalent
157+
// overload set in base classes, so we merge it with the
158+
// other FunctionInfos into a new OverloadsInfo
159+
OverloadsInfo O(contextId, function->Name);
75160
addMember(O, *function);
76-
*it = O.id;
77-
auto const itOffset = it - ids.begin();
78-
for (auto otherIt = it + 1; otherIt != ids.end(); ++otherIt)
161+
*functionIdIt = O.id;
162+
auto const itOffset = functionIdIt - functionIds.begin();
163+
for (auto otherIt = functionIdIt + 1; otherIt != functionIds.end(); ++otherIt)
79164
{
80165
Info* otherInfoPtr = corpus_.find(*otherIt);
81166
MRDOCS_CHECK_OR_CONTINUE(otherInfoPtr);
@@ -84,10 +169,10 @@ foldOverloads(SymbolID const& parent, std::vector<SymbolID>& ids)
84169
if (function->Name == otherFunction->Name)
85170
{
86171
addMember(O, *otherFunction);
87-
otherIt = std::prev(ids.erase(otherIt));
172+
otherIt = std::prev(functionIds.erase(otherIt));
88173
}
89174
}
90-
it = ids.begin() + itOffset;
175+
functionIdIt = functionIds.begin() + itOffset;
91176
corpus_.info_.emplace(std::make_unique<OverloadsInfo>(std::move(O)));
92177
}
93178
}
@@ -105,6 +190,22 @@ void
105190
OverloadsFinalizer::
106191
operator()(RecordInfo& I)
107192
{
193+
MRDOCS_CHECK_OR(!finalized_.contains(I.id));
194+
for (auto& b: I.Bases)
195+
{
196+
auto& BT = b.Type;
197+
MRDOCS_CHECK_OR(BT);
198+
MRDOCS_CHECK_OR(BT->isNamed());
199+
auto& NT = dynamic_cast<NamedTypeInfo&>(*BT);
200+
MRDOCS_CHECK_OR(NT.Name);
201+
auto& NI = dynamic_cast<NameInfo&>(*NT.Name);
202+
MRDOCS_CHECK_OR(NI.id);
203+
Info* baseInfo = corpus_.find(NI.id);
204+
MRDOCS_CHECK_OR(baseInfo);
205+
auto* baseRecord = dynamic_cast<RecordInfo*>(baseInfo);
206+
MRDOCS_CHECK_OR(baseRecord);
207+
operator()(*baseRecord);
208+
}
108209
foldOverloads(I.id, I.Interface.Public.Functions);
109210
foldOverloads(I.id, I.Interface.Protected.Functions);
110211
foldOverloads(I.id, I.Interface.Private.Functions);
@@ -114,6 +215,7 @@ operator()(RecordInfo& I)
114215
foldRecordMembers(I.Interface.Public.Records);
115216
foldRecordMembers(I.Interface.Protected.Records);
116217
foldRecordMembers(I.Interface.Private.Records);
218+
finalized_.emplace(I.id);
117219
}
118220

119221
} // clang::mrdocs

src/lib/Metadata/Finalizers/OverloadsFinalizer.hpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,18 @@ namespace clang::mrdocs {
2727
class OverloadsFinalizer
2828
{
2929
CorpusImpl& corpus_;
30+
std::set<SymbolID> finalized_;
3031

3132
void
3233
foldRecordMembers(std::vector<SymbolID> const& ids);
3334

3435
void
35-
foldNamespaceMembers(std::vector<SymbolID> const& ids);
36+
foldNamespaceMembers(std::vector<SymbolID> const& namespaceIds);
3637

3738
void
38-
foldOverloads(SymbolID const& parent, std::vector<SymbolID>& ids);
39+
foldOverloads(
40+
SymbolID const& contextId,
41+
std::vector<SymbolID>& functionIds);
3942

4043
public:
4144
OverloadsFinalizer(CorpusImpl& corpus)

0 commit comments

Comments
 (0)