Skip to content

Commit 2bd8576

Browse files
committed
fix: global namespace safename
1 parent 0673c9b commit 2bd8576

File tree

1 file changed

+136
-7
lines changed

1 file changed

+136
-7
lines changed

src/lib/Support/SafeNames.cpp

Lines changed: 136 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ class SafeNames::Impl
3030
{
3131
Corpus const& corpus_;
3232

33+
// name used for the global namespace
34+
std::string global_ns_;
35+
3336
// store all info required to generate a safename
3437
struct SafeNameInfo
3538
{
@@ -44,6 +47,11 @@ class SafeNames::Impl
4447

4548
std::unordered_map<SymbolID, SafeNameInfo> map_;
4649

50+
// maps unqualified names to all symbols
51+
// with that name within the current scope
52+
std::unordered_multimap<
53+
std::string_view, SafeNameInfo*> disambiguation_map__;
54+
4755
std::string_view
4856
getReserved(const Info& I)
4957
{
@@ -97,16 +105,13 @@ class SafeNames::Impl
97105
getUnqualified(
98106
const Info& I)
99107
{
108+
MRDOX_ASSERT(I.id != SymbolID::zero);
100109
return visit(I, [&]<typename T>(
101110
const T& t) -> std::string_view
102111
{
103112
// namespaces can be unnamed (i.e. anonymous)
104113
if constexpr(T::isNamespace())
105114
{
106-
// special case for the global namespace
107-
if(t.id == SymbolID::zero)
108-
return std::string_view();
109-
110115
if(t.specs.isAnonymous.get())
111116
return getReserved(t);
112117
MRDOX_ASSERT(! t.Name.empty());
@@ -184,6 +189,73 @@ class SafeNames::Impl
184189

185190
//--------------------------------------------
186191

192+
void
193+
buildSafeMember(
194+
const Info& I,
195+
std::string_view name)
196+
{
197+
// generate the unqualified name and SymbolID string
198+
auto it = map_.emplace(I.id, SafeNameInfo(
199+
name, 0, toBase16(I.id, true))).first;
200+
#if 0
201+
// update the disambiguation map
202+
auto [disambig_it, disambig_emplaced] =
203+
disambiguation_map_.try_emplace(name);
204+
// if there are other symbols with the same name, then disambiguation
205+
// is required. iterate over the other symbols with the same unqualified name,
206+
// and calculate the minimum number of characters from the SymbolID needed
207+
// to uniquely identify each symbol. then, update all symbols with the new value.
208+
if(! disambig_emplaced)
209+
{
210+
std::uint8_t n_chars = 0;
211+
std::string_view id_str = it->second.id_str;
212+
for(const SymbolID& other_id : disambig_it->second)
213+
{
214+
auto& other = map_.at(other_id);
215+
auto mismatch_it = std::ranges::mismatch(
216+
id_str, other.id_str).in1;
217+
std::uint8_t n_required = std::distance(
218+
id_str.begin(), mismatch_it) + 1;
219+
n_chars = std::max({
220+
n_chars, other.disambig_chars, n_required});
221+
}
222+
223+
MRDOX_ASSERT(n_chars);
224+
// update the number of disambiguation characters for each symbol
225+
it->second.disambig_chars = n_chars;
226+
for(const SymbolID& other_id : disambig_it->second)
227+
map_.at(other_id).disambig_chars = n_chars;
228+
}
229+
disambig_it->second.push_back(I.id);
230+
#else
231+
std::uint8_t n_chars = 0;
232+
std::string_view id_str = it->second.id_str;
233+
auto [first, last] = disambiguation_map__.equal_range(name);
234+
for(const auto& other : std::ranges::subrange(
235+
first, last) | std::views::values)
236+
{
237+
//auto& other = map_.at(other_id);
238+
auto mismatch_it = std::ranges::mismatch(
239+
id_str, other->id_str).in1;
240+
std::uint8_t n_required = std::distance(
241+
id_str.begin(), mismatch_it) + 1;
242+
n_chars = std::max({
243+
n_chars, other->disambig_chars, n_required});
244+
}
245+
246+
if(n_chars)
247+
{
248+
for(const auto& other : std::ranges::subrange(
249+
first, last) | std::views::values)
250+
other->disambig_chars = n_chars;
251+
it->second.disambig_chars = n_chars;
252+
}
253+
disambiguation_map__.emplace(name, &it->second);
254+
255+
#endif
256+
}
257+
258+
#if 0
187259
template<typename Range>
188260
void
189261
buildSafeMembers(
@@ -237,18 +309,32 @@ class SafeNames::Impl
237309
disambig_it->second.push_back(I->id);
238310
}
239311
}
312+
#endif
240313

241314
//--------------------------------------------
242315

243316
public:
244-
explicit
245-
Impl(Corpus const& corpus)
317+
Impl(Corpus const& corpus, std::string_view global_ns)
246318
: corpus_(corpus)
319+
, global_ns_(global_ns)
247320
{
321+
#if 0
248322
map_.try_emplace(SymbolID::zero, SafeNameInfo(
249323
"global_namespace", 0, toBase16(SymbolID::zero, true)));
250324

251325
visit(corpus_.globalNamespace(), *this);
326+
#else
327+
const NamespaceInfo& global =
328+
corpus_.globalNamespace();
329+
// treat the global namespace as-if its "name"
330+
// is in the same scope as its members
331+
buildSafeMember(global, global_ns_);
332+
visit(global, *this);
333+
// after generating safenames for every symbol,
334+
// set the number of disambiguation characters
335+
// used for the global namespace to zero
336+
map_.at(global.id).disambig_chars = 0;
337+
#endif
252338
}
253339

254340
void
@@ -297,6 +383,48 @@ class SafeNames::Impl
297383
getSafeUnqualified(result, id);
298384
}
299385

386+
template<typename InfoTy, typename Fn>
387+
void traverse(const InfoTy& I, Fn&& F)
388+
{
389+
static constexpr auto getMember = [](const auto& M)
390+
{
391+
if constexpr(requires { M.Specialized; })
392+
return M.Specialized;
393+
else
394+
return M;
395+
};
396+
397+
if constexpr(InfoTy::isSpecialization() ||
398+
InfoTy::isNamespace() || InfoTy::isRecord())
399+
{
400+
std::ranges::for_each(I.Members, F, getMember);
401+
}
402+
403+
if constexpr(InfoTy::isNamespace() || InfoTy::isRecord())
404+
{
405+
std::ranges::for_each(I.Specializations, F);
406+
}
407+
}
408+
409+
template<typename InfoTy>
410+
void operator()(const InfoTy& I)
411+
{
412+
traverse(I, [this](const SymbolID& id)
413+
{
414+
if(const Info* M = corpus_.find(id))
415+
buildSafeMember(*M, getUnqualified(*M));
416+
});
417+
// clear the disambiguation map after visiting the members,
418+
// then build disambiguation information for each member
419+
disambiguation_map__.clear();
420+
traverse(I, [this](const SymbolID& id)
421+
{
422+
if(const Info* M = corpus_.find(id))
423+
visit(*M, *this);
424+
});
425+
}
426+
427+
#if 0
300428
template<class T>
301429
void operator()(T const& I)
302430
{
@@ -330,13 +458,14 @@ class SafeNames::Impl
330458
}
331459
}
332460
}
461+
#endif
333462
};
334463

335464
//------------------------------------------------
336465

337466
SafeNames::
338467
SafeNames(Corpus const& corpus)
339-
: impl_(std::make_unique<Impl>(corpus))
468+
: impl_(std::make_unique<Impl>(corpus, "index"))
340469
{
341470
}
342471

0 commit comments

Comments
 (0)