@@ -28,54 +28,139 @@ foldRecordMembers(std::vector<SymbolID> const& ids)
2828
2929void
3030OverloadsFinalizer::
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+
4397void
4498OverloadsFinalizer::
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
105190OverloadsFinalizer::
106191operator ()(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
0 commit comments