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 |
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 '/' |
33 | std::string llvm::logicalview::transformPath(StringRef Path) { |
34 | std::string Name(Path); |
35 | std::transform(first: Name.begin(), last: Name.end(), result: Name.begin(), unary_op: tolower); |
36 | std::replace(first: Name.begin(), last: Name.end(), old_value: '\\', new_value: '/'); |
37 | |
38 | // Remove all duplicate slashes. |
39 | size_t Pos = 0; |
40 | while ((Pos = Name.find(s: "//" , pos: Pos)) != std::string::npos) |
41 | Name.erase(pos: Pos, n: 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 | // '/', '\', '<', '>', '.', ':', '%', '*', '?', '|', '"', ' '. |
50 | std::string llvm::logicalview::flattenedFilePath(StringRef Path) { |
51 | std::string Name(Path); |
52 | std::transform(first: Name.begin(), last: Name.end(), result: Name.begin(), unary_op: tolower); |
53 | |
54 | const char *CharSet = "/\\<>.:%*?|\" " ; |
55 | char *Input = Name.data(); |
56 | while (Input && *Input) { |
57 | Input = strpbrk(s: Input, accept: 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 | |
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(Elt: 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(Elt: LexicalEntry(Current, Length - 1)); |
116 | LLVM_DEBUG({ PrintLexicalEntry(); }); |
117 | return Indexes; |
118 | } |
119 | |
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(args: StringRef(), args&: Name); |
127 | |
128 | LexicalEntry BeginEntry = Indexes.front(); |
129 | LexicalEntry EndEntry = Indexes[Indexes.size() - 2]; |
130 | StringRef Outer = |
131 | Name.substr(Start: BeginEntry.first, N: EndEntry.second - BeginEntry.first + 1); |
132 | |
133 | LexicalEntry LastEntry = Indexes.back(); |
134 | StringRef Inner = |
135 | Name.substr(Start: LastEntry.first, N: LastEntry.second - LastEntry.first + 1); |
136 | |
137 | return std::make_tuple(args&: Outer, args&: Inner); |
138 | } |
139 | |
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 | x: Name.substr(Start: Entry.first, N: Entry.second - Entry.first + 1)); |
149 | |
150 | return Components; |
151 | } |
152 | |
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 | |