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