CMS 3D CMS Logo

TypeDemangler.cc
Go to the documentation of this file.
1 #include <cxxabi.h>
2 #include <cctype>
3 #include <string>
4 #include <regex>
6 
7 /********************************************************************
8  TypeDemangler is used to demangle the mangled name provided by type_info into the type name.
9 
10  The conventions used (e.g. const qualifiers before identifiers, no spaces after commas)
11  are chosen to match the type names that can be used by the plug-in manager to load data dictionaries.
12  It also strips comparators from (multi) maps or sets, and always strips allocators.
13 
14  This demangler is platform dependent. This version works for gcc.
15 
16  Known limitations:
17 
18  0) It is platform dependent. See above.
19 
20  1) It does not demangle function names, only type names.
21 
22  2) If an enum value is used as a non-type template parameter, the demangled name cannot
23  be used successfully to load the dictionary. This is because the enumerator value name
24  is not available in the mangled name (on this platform).
25 
26 ********************************************************************/
27 namespace {
28  void reformatter(std::string& input, char const* exp, char const* format) {
29  std::regex regexp(exp, std::regex::egrep);
30  while (std::regex_match(input, regexp)) {
31  std::string newstring = std::regex_replace(input, regexp, format);
32  input.swap(newstring);
33  }
34  }
35 
36  void removeParameter(std::string& demangledName, std::string const& toRemove) {
37  std::string::size_type const asize = toRemove.size();
38  char const* const delimiters = "<>";
39  std::string::size_type index = std::string::npos;
40  while ((index = demangledName.find(toRemove)) != std::string::npos) {
41  int depth = 1;
42  std::string::size_type inx = index + asize;
43  while ((inx = demangledName.find_first_of(delimiters, inx)) != std::string::npos) {
44  if (demangledName[inx] == '<') {
45  ++depth;
46  } else {
47  --depth;
48  if (depth == 0) {
49  demangledName.erase(index, inx + 1 - index);
50  if (demangledName[index] == ' ' && (index == 0 || demangledName[index - 1] != '>')) {
51  demangledName.erase(index, 1);
52  }
53  break;
54  }
55  }
56  ++inx;
57  }
58  }
59  }
60 
61  void constBeforeIdentifier(std::string& demangledName) {
62  std::string const toBeMoved(" const");
63  std::string::size_type const asize = toBeMoved.size();
64  std::string::size_type index = std::string::npos;
65  while ((index = demangledName.find(toBeMoved)) != std::string::npos) {
66  demangledName.erase(index, asize);
67  int depth = 0;
68  for (std::string::size_type inx = index - 1; inx > 0; --inx) {
69  char const c = demangledName[inx];
70  if (c == '>') {
71  ++depth;
72  } else if (depth > 0) {
73  if (c == '<')
74  --depth;
75  } else if (c == '<' || c == ',') {
76  demangledName.insert(inx + 1, "const ");
77  break;
78  }
79  }
80  }
81  }
82 } // namespace
83 
84 namespace edm {
85  void replaceString(std::string& demangledName, std::string const& from, std::string const& to) {
86  // from must not be a substring of to.
87  std::string::size_type length = from.size();
89  while ((pos = demangledName.find(from, pos)) != std::string::npos) {
90  demangledName.replace(pos, length, to);
91  }
92  }
93 
94  std::string typeDemangle(char const* mangledName) {
95  int status = 0;
96  size_t* const nullSize = nullptr;
97  char* const null = nullptr;
98 
99  // The demangled C style string is allocated with malloc, so it must be deleted with free().
100  char* demangled = abi::__cxa_demangle(mangledName, null, nullSize, &status);
101  if (status != 0) {
102  throw cms::Exception("Demangling error") << " '" << mangledName << "'\n";
103  }
104  std::string demangledName(demangled);
105  free(demangled);
106  // We must use the same conventions previously used by REFLEX.
107  // The order of these is important.
108  // No space after comma
109  replaceString(demangledName, ", ", ",");
110  // No space before opening square bracket
111  replaceString(demangledName, " [", "[");
112  // clang libc++ uses __1:: namespace
113  replaceString(demangledName, "std::__1::", "std::");
114  // new gcc abi uses __cxx11:: namespace
115  replaceString(demangledName, "std::__cxx11::", "std::");
116  // Strip default allocator
117  std::string const allocator(",std::allocator<");
118  removeParameter(demangledName, allocator);
119  // Strip default comparator
120  std::string const comparator(",std::less<");
121  removeParameter(demangledName, comparator);
122  // Put const qualifier before identifier.
123  constBeforeIdentifier(demangledName);
124  // No two consecutive '>'
125  replaceString(demangledName, ">>", "> >");
126  // No u or l qualifiers for integers.
127  reformatter(demangledName, "(.*[<,][0-9]+)[ul]l*([,>].*)", "$1$2");
128  // For ROOT 6 and beyond, replace 'unsigned long long' with 'ULong64_t'
129  replaceString(demangledName, "unsigned long long", "ULong64_t");
130  // For ROOT 6 and beyond, replace 'long long' with 'Long64_t'
131  replaceString(demangledName, "long long", "Long64_t");
132  return demangledName;
133  }
134 } // namespace edm
void replaceString(std::string &demangledName, std::string const &from, std::string const &to)
uint16_t size_type
static std::string const input
Definition: EdmProvDump.cc:48
demangled
Definition: symbols.py:62
std::string typeDemangle(char const *mangledName)
HLT enums.