FriendlyName.cc
Go to the documentation of this file.
2 // vim: set sw=2 expandtab :
3 
5 
6 #include <map>
7 #include <mutex>
8 #include <regex>
9 #include <string>
10 
11 // NOTE: This should probably be rewritten so that we break the class
12 // name into a tree where the template arguments are the node. On the
13 // way down the tree we look for '<' or ',' and on the way up (caused by
14 // finding a '>') we can apply the transformation to the output string
15 // based on the class name for the templated class. Up front we'd
16 // register a class name to a transformation function (which would
17 // probably take a std::vector<std::string> which holds the results of
18 // the node transformations).
19 
20 namespace {
21 
22  std::regex const reAllSpaces{" +"};
23  std::regex const reAssns{"art::Assns"};
24  std::regex const reBeginSpace{"^ +"};
25  std::regex const reComma{","};
26  std::regex const reEndSpace{" +$"};
27  std::regex const reParens{"(\\(|\\))"};
28  std::regex const reFirstTwoArgs{"^([^,]+),([^,]+)"};
29  std::regex const reLong{"long "};
30  std::regex const reLongLong{"Long64_t"};
31  std::regex const reMapVector{"cet::map_vector"};
32  std::regex const reMapVectorKey{"cet::map_vector_key"};
33  std::regex const reString{"(?:std::basic_string<char>|std::string)"};
34  std::regex const reTemplateArgs{"([^<]*)<(.*)>$"};
35  std::regex const reTemplateClass{"([^<>,]+<[^<>]*>)"};
36  std::regex const reULongLong{"ULong64_t"};
37  std::regex const reUnsigned{"unsigned "};
38  std::regex const reVector{"std::vector"};
39  std::regex const reWrapper{"art::Wrapper<(.*)>"};
40 
41  std::string const emptyString{};
42 
44  removeExtraSpaces(std::string const& in)
45  {
46  return std::regex_replace(std::regex_replace(in, reBeginSpace, emptyString),
47  reEndSpace,
48  emptyString);
49  }
50 
52  removeAllSpaces(std::string const& in)
53  {
54  return std::regex_replace(in, reAllSpaces, emptyString);
55  }
56 
58  escapeParens(std::string const& in)
59  {
60  return std::regex_replace(in, reParens, "\\$1");
61  }
62 
64  standardRenames(std::string const& in)
65  {
66  std::string name{std::regex_replace(in, reWrapper, "$1")};
67  name = std::regex_replace(name, reString, "String");
68  name = std::regex_replace(name, reUnsigned, "u");
69  name = std::regex_replace(name, reLong, "l");
70  name = std::regex_replace(name, reULongLong, "ull");
71  name = std::regex_replace(name, reLongLong, "ll");
72  name = std::regex_replace(name, reVector, "s");
73  name = std::regex_replace(name, reMapVectorKey, "mvk");
74  name = std::regex_replace(name, reMapVector, "mv");
75  return name;
76  }
77 
78  // Declaration required here because handleTemplateArguments and
79  // subFriendlyName call each other.
80  std::string handleTemplateArguments(std::string const&, std::string const&);
82  subFriendlyName(std::string const& iFullName)
83  {
84  std::string result{removeExtraSpaces(iFullName)};
85  std::smatch theMatch;
86  if (std::regex_match(result, theMatch, reTemplateArgs)) {
87  std::string const cMatch{theMatch.str(1)};
88  std::string const aMatch{theMatch.str(2)};
89  std::string const theSub{handleTemplateArguments(cMatch, aMatch)};
90  // If a type (e.g.) A was declared in an anonymous namespace,
91  // the demangled typename can be (anonymous namespace)::A. The
92  // parentheses must be escaped so that they do not interfere
93  // with the regex library.
94  std::regex const eMatch{std::string{"^"} + escapeParens(cMatch) + '<' +
95  escapeParens(aMatch) + '>'};
96  result = std::regex_replace(result, eMatch, theSub + cMatch);
97  }
98  return result;
99  }
100 
101  void
102  maybeSwapFirstTwoArgs(std::string& result)
103  {
104  std::smatch theMatch;
105  if (std::regex_search(result, theMatch, reFirstTwoArgs) &&
106  (theMatch.str(1) > theMatch.str(2))) {
107  result = std::regex_replace(result, reFirstTwoArgs, "$2,$1");
108  }
109  }
110 
112  handleTemplateArguments(std::string const& cName, std::string const& tArgs)
113  {
114  std::string result{removeExtraSpaces(tArgs)};
115  bool shouldStop{false};
116  while (!shouldStop) {
117  if (std::string::npos != result.find_first_of("<")) {
118  std::smatch theMatch;
119  if (std::regex_search(result, theMatch, reTemplateClass)) {
120  std::string const templateClass{theMatch.str(1)};
121  std::string const friendlierName{
122  removeAllSpaces(subFriendlyName(templateClass))};
123  result = std::regex_replace(
124  result, std::regex(templateClass), friendlierName);
125  } else {
127  << "No template match for \"" << result << '"';
128  }
129  } else {
130  shouldStop = true;
131  }
132  }
133  if (std::regex_match(cName, reAssns)) {
134  maybeSwapFirstTwoArgs(result);
135  }
136  result = std::regex_replace(result, reComma, emptyString);
137  return result;
138  }
139 
140 } // unnamed namespace
141 
144 {
145  static std::recursive_mutex s_mutex;
146  static std::map<std::string, std::string> s_nameMap;
147  std::lock_guard sentry{s_mutex};
148  auto entry = s_nameMap.find(iFullName);
149  if (entry == s_nameMap.end()) {
150  entry =
151  s_nameMap.emplace(iFullName, subFriendlyName(standardRenames(iFullName)))
152  .first;
153  }
154  return entry->second;
155 }
static QCString name
Definition: declinfo.cpp:673
QList< Entry > entry
static QCString result
std::string string
Definition: nybbler.cc:12
std::string friendlyName(std::string const &iFullName)
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66