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 | llvm::transform(Range&: Name, d_first: Name.begin(), F: tolower); |
34 | llvm::replace(Range&: Name, OldValue: '\\', NewValue: '/'); |
35 | |
36 | // Remove all duplicate slashes. |
37 | size_t Pos = 0; |
38 | while ((Pos = Name.find(s: "//" , pos: Pos)) != std::string::npos) |
39 | Name.erase(pos: Pos, n: 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 | llvm::transform(Range&: Name, d_first: Name.begin(), F: tolower); |
51 | |
52 | const char *CharSet = "/\\<>.:%*?|\" " ; |
53 | char *Input = Name.data(); |
54 | while (Input && *Input) { |
55 | Input = strpbrk(s: Input, accept: 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(Elt: 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(Elt: 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(args: StringRef(), args&: Name); |
125 | |
126 | LexicalEntry BeginEntry = Indexes.front(); |
127 | LexicalEntry EndEntry = Indexes[Indexes.size() - 2]; |
128 | StringRef Outer = |
129 | Name.substr(Start: BeginEntry.first, N: EndEntry.second - BeginEntry.first + 1); |
130 | |
131 | LexicalEntry LastEntry = Indexes.back(); |
132 | StringRef Inner = |
133 | Name.substr(Start: LastEntry.first, N: LastEntry.second - LastEntry.first + 1); |
134 | |
135 | return std::make_tuple(args&: Outer, args&: 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 | x: Name.substr(Start: Entry.first, N: 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 | |