1313
1414namespace 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-
4216namespace {
4317SymbolID
4418findBaseClassPermutation (
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
95116void
96117OverloadsFinalizer::
97118foldOverloads (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+
179261void
180262OverloadsFinalizer::
181263operator ()(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
188282void
@@ -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
0 commit comments