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