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