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 18using namespace llvm; 19using namespace llvm::logicalview; 20 21#define DEBUG_TYPE "Support" 22 23namespace { 24// Unique string pool instance used by all logical readers. 25LVStringPool StringPool; 26} // namespace 27LVStringPool &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 '/' 33std::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// '/', '\', '<', '>', '.', ':', '%', '*', '?', '|', '"', ' '. 50std::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 64using LexicalEntry = std::pair<size_t, size_t>; 65using LexicalIndexes = SmallVector<LexicalEntry, 10>; 66 67static 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 120LVLexicalComponent 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 140LVStringRefs 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 153std::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