@@ -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
116102void
117103OverloadsFinalizer::
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+
235354namespace {
236- template <class T >
355+ template <class T , range_of<SymbolID> R >
237356constexpr
238357auto
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
0 commit comments