1bdd1243dSDimitry Andric //===-- LVSupport.cpp -----------------------------------------------------===//
2bdd1243dSDimitry Andric //
3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bdd1243dSDimitry Andric //
7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
8bdd1243dSDimitry Andric //
9bdd1243dSDimitry Andric // This implements the supporting functions.
10bdd1243dSDimitry Andric //
11bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
12bdd1243dSDimitry Andric 
13bdd1243dSDimitry Andric #include "llvm/DebugInfo/LogicalView/Core/LVSupport.h"
14bdd1243dSDimitry Andric #include "llvm/Support/FormatAdapters.h"
15bdd1243dSDimitry Andric #include "llvm/Support/FormatVariadic.h"
16bdd1243dSDimitry Andric #include <iomanip>
17bdd1243dSDimitry Andric 
18bdd1243dSDimitry Andric using namespace llvm;
19bdd1243dSDimitry Andric using namespace llvm::logicalview;
20bdd1243dSDimitry Andric 
21bdd1243dSDimitry Andric #define DEBUG_TYPE "Support"
22bdd1243dSDimitry Andric 
231ac55f4cSDimitry Andric namespace {
241ac55f4cSDimitry Andric // Unique string pool instance used by all logical readers.
251ac55f4cSDimitry Andric LVStringPool StringPool;
261ac55f4cSDimitry Andric } // namespace
getStringPool()271ac55f4cSDimitry Andric LVStringPool &llvm::logicalview::getStringPool() { return StringPool; }
281ac55f4cSDimitry Andric 
29bdd1243dSDimitry Andric // Perform the following transformations to the given 'Path':
30bdd1243dSDimitry Andric // - all characters to lowercase.
31bdd1243dSDimitry Andric // - '\\' into '/' (Platform independent).
32bdd1243dSDimitry Andric // - '//' into '/'
transformPath(StringRef Path)33bdd1243dSDimitry Andric std::string llvm::logicalview::transformPath(StringRef Path) {
34bdd1243dSDimitry Andric   std::string Name(Path);
35bdd1243dSDimitry Andric   std::transform(Name.begin(), Name.end(), Name.begin(), tolower);
36bdd1243dSDimitry Andric   std::replace(Name.begin(), Name.end(), '\\', '/');
37bdd1243dSDimitry Andric 
38bdd1243dSDimitry Andric   // Remove all duplicate slashes.
39bdd1243dSDimitry Andric   size_t Pos = 0;
40bdd1243dSDimitry Andric   while ((Pos = Name.find("//", Pos)) != std::string::npos)
41bdd1243dSDimitry Andric     Name.erase(Pos, 1);
42bdd1243dSDimitry Andric 
43bdd1243dSDimitry Andric   return Name;
44bdd1243dSDimitry Andric }
45bdd1243dSDimitry Andric 
46bdd1243dSDimitry Andric // Convert the given 'Path' to lowercase and change any matching character
47bdd1243dSDimitry Andric // from 'CharSet' into '_'.
48bdd1243dSDimitry Andric // The characters in 'CharSet' are:
49bdd1243dSDimitry Andric //   '/', '\', '<', '>', '.', ':', '%', '*', '?', '|', '"', ' '.
flattenedFilePath(StringRef Path)50bdd1243dSDimitry Andric std::string llvm::logicalview::flattenedFilePath(StringRef Path) {
51bdd1243dSDimitry Andric   std::string Name(Path);
52bdd1243dSDimitry Andric   std::transform(Name.begin(), Name.end(), Name.begin(), tolower);
53bdd1243dSDimitry Andric 
54bdd1243dSDimitry Andric   const char *CharSet = "/\\<>.:%*?|\" ";
55bdd1243dSDimitry Andric   char *Input = Name.data();
56bdd1243dSDimitry Andric   while (Input && *Input) {
57bdd1243dSDimitry Andric     Input = strpbrk(Input, CharSet);
58bdd1243dSDimitry Andric     if (Input)
59bdd1243dSDimitry Andric       *Input++ = '_';
60bdd1243dSDimitry Andric   };
61bdd1243dSDimitry Andric   return Name;
62bdd1243dSDimitry Andric }
63*06c3fb27SDimitry Andric 
64*06c3fb27SDimitry Andric using LexicalEntry = std::pair<size_t, size_t>;
65*06c3fb27SDimitry Andric using LexicalIndexes = SmallVector<LexicalEntry, 10>;
66*06c3fb27SDimitry Andric 
getAllLexicalIndexes(StringRef Name)67*06c3fb27SDimitry Andric static LexicalIndexes getAllLexicalIndexes(StringRef Name) {
68*06c3fb27SDimitry Andric   if (Name.empty())
69*06c3fb27SDimitry Andric     return {};
70*06c3fb27SDimitry Andric 
71*06c3fb27SDimitry Andric   size_t AngleCount = 0;
72*06c3fb27SDimitry Andric   size_t ColonSeen = 0;
73*06c3fb27SDimitry Andric   size_t Current = 0;
74*06c3fb27SDimitry Andric 
75*06c3fb27SDimitry Andric   LexicalIndexes Indexes;
76*06c3fb27SDimitry Andric 
77*06c3fb27SDimitry Andric #ifndef NDEBUG
78*06c3fb27SDimitry Andric   auto PrintLexicalEntry = [&]() {
79*06c3fb27SDimitry Andric     LexicalEntry Entry = Indexes.back();
80*06c3fb27SDimitry Andric     llvm::dbgs() << formatv(
81*06c3fb27SDimitry Andric         "'{0}:{1}', '{2}'\n", Entry.first, Entry.second,
82*06c3fb27SDimitry Andric         Name.substr(Entry.first, Entry.second - Entry.first + 1));
83*06c3fb27SDimitry Andric   };
84*06c3fb27SDimitry Andric #endif
85*06c3fb27SDimitry Andric 
86*06c3fb27SDimitry Andric   size_t Length = Name.size();
87*06c3fb27SDimitry Andric   for (size_t Index = 0; Index < Length; ++Index) {
88*06c3fb27SDimitry Andric     LLVM_DEBUG({
89*06c3fb27SDimitry Andric       llvm::dbgs() << formatv("Index: '{0}', Char: '{1}'\n", Index,
90*06c3fb27SDimitry Andric                               Name[Index]);
91*06c3fb27SDimitry Andric     });
92*06c3fb27SDimitry Andric     switch (Name[Index]) {
93*06c3fb27SDimitry Andric     case '<':
94*06c3fb27SDimitry Andric       ++AngleCount;
95*06c3fb27SDimitry Andric       break;
96*06c3fb27SDimitry Andric     case '>':
97*06c3fb27SDimitry Andric       --AngleCount;
98*06c3fb27SDimitry Andric       break;
99*06c3fb27SDimitry Andric     case ':':
100*06c3fb27SDimitry Andric       ++ColonSeen;
101*06c3fb27SDimitry Andric       break;
102*06c3fb27SDimitry Andric     }
103*06c3fb27SDimitry Andric     if (ColonSeen == 2) {
104*06c3fb27SDimitry Andric       if (!AngleCount) {
105*06c3fb27SDimitry Andric         Indexes.push_back(LexicalEntry(Current, Index - 2));
106*06c3fb27SDimitry Andric         Current = Index + 1;
107*06c3fb27SDimitry Andric         LLVM_DEBUG({ PrintLexicalEntry(); });
108*06c3fb27SDimitry Andric       }
109*06c3fb27SDimitry Andric       ColonSeen = 0;
110*06c3fb27SDimitry Andric       continue;
111*06c3fb27SDimitry Andric     }
112*06c3fb27SDimitry Andric   }
113*06c3fb27SDimitry Andric 
114*06c3fb27SDimitry Andric   // Store last component.
115*06c3fb27SDimitry Andric   Indexes.push_back(LexicalEntry(Current, Length - 1));
116*06c3fb27SDimitry Andric   LLVM_DEBUG({ PrintLexicalEntry(); });
117*06c3fb27SDimitry Andric   return Indexes;
118*06c3fb27SDimitry Andric }
119*06c3fb27SDimitry Andric 
getInnerComponent(StringRef Name)120*06c3fb27SDimitry Andric LVLexicalComponent llvm::logicalview::getInnerComponent(StringRef Name) {
121*06c3fb27SDimitry Andric   if (Name.empty())
122*06c3fb27SDimitry Andric     return {};
123*06c3fb27SDimitry Andric 
124*06c3fb27SDimitry Andric   LexicalIndexes Indexes = getAllLexicalIndexes(Name);
125*06c3fb27SDimitry Andric   if (Indexes.size() == 1)
126*06c3fb27SDimitry Andric     return std::make_tuple(StringRef(), Name);
127*06c3fb27SDimitry Andric 
128*06c3fb27SDimitry Andric   LexicalEntry BeginEntry = Indexes.front();
129*06c3fb27SDimitry Andric   LexicalEntry EndEntry = Indexes[Indexes.size() - 2];
130*06c3fb27SDimitry Andric   StringRef Outer =
131*06c3fb27SDimitry Andric       Name.substr(BeginEntry.first, EndEntry.second - BeginEntry.first + 1);
132*06c3fb27SDimitry Andric 
133*06c3fb27SDimitry Andric   LexicalEntry LastEntry = Indexes.back();
134*06c3fb27SDimitry Andric   StringRef Inner =
135*06c3fb27SDimitry Andric       Name.substr(LastEntry.first, LastEntry.second - LastEntry.first + 1);
136*06c3fb27SDimitry Andric 
137*06c3fb27SDimitry Andric   return std::make_tuple(Outer, Inner);
138*06c3fb27SDimitry Andric }
139*06c3fb27SDimitry Andric 
getAllLexicalComponents(StringRef Name)140*06c3fb27SDimitry Andric LVStringRefs llvm::logicalview::getAllLexicalComponents(StringRef Name) {
141*06c3fb27SDimitry Andric   if (Name.empty())
142*06c3fb27SDimitry Andric     return {};
143*06c3fb27SDimitry Andric 
144*06c3fb27SDimitry Andric   LexicalIndexes Indexes = getAllLexicalIndexes(Name);
145*06c3fb27SDimitry Andric   LVStringRefs Components;
146*06c3fb27SDimitry Andric   for (const LexicalEntry &Entry : Indexes)
147*06c3fb27SDimitry Andric     Components.push_back(
148*06c3fb27SDimitry Andric         Name.substr(Entry.first, Entry.second - Entry.first + 1));
149*06c3fb27SDimitry Andric 
150*06c3fb27SDimitry Andric   return Components;
151*06c3fb27SDimitry Andric }
152*06c3fb27SDimitry Andric 
getScopedName(const LVStringRefs & Components,StringRef BaseName)153*06c3fb27SDimitry Andric std::string llvm::logicalview::getScopedName(const LVStringRefs &Components,
154*06c3fb27SDimitry Andric                                              StringRef BaseName) {
155*06c3fb27SDimitry Andric   if (Components.empty())
156*06c3fb27SDimitry Andric     return {};
157*06c3fb27SDimitry Andric   std::string Name(BaseName);
158*06c3fb27SDimitry Andric   raw_string_ostream Stream(Name);
159*06c3fb27SDimitry Andric   if (BaseName.size())
160*06c3fb27SDimitry Andric     Stream << "::";
161*06c3fb27SDimitry Andric   Stream << Components[0];
162*06c3fb27SDimitry Andric   for (LVStringRefs::size_type Index = 1; Index < Components.size(); ++Index)
163*06c3fb27SDimitry Andric     Stream << "::" << Components[Index];
164*06c3fb27SDimitry Andric   return Name;
165*06c3fb27SDimitry Andric }
166