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