Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-03-17 11:03:54

0001 #include <cxxabi.h>
0002 #include <cctype>
0003 #include <string>
0004 #include <regex>
0005 #include "FWCore/Utilities/interface/Exception.h"
0006 
0007 /********************************************************************
0008         TypeDemangler is used to demangle the mangled name provided by type_info into the type name.
0009 
0010         The conventions used (e.g. const qualifiers before identifiers, no spaces after commas)
0011         are chosen to match the type names that can be used by the plug-in manager to load data dictionaries.
0012         It also strips comparators from (multi) maps or sets, and always strips allocators.
0013 
0014         This demangler is platform dependent.  This version works for gcc.
0015 
0016         Known limitations:
0017 
0018         0) It is platform dependent. See above.
0019 
0020         1) It does not demangle function names, only type names.
0021 
0022         2) If an enum value is used as a non-type template parameter, the demangled name cannot
0023         be used successfully to load the dictionary.  This is because the enumerator value name
0024         is not available in the mangled name (on this platform).
0025 
0026 ********************************************************************/
0027 namespace {
0028   void reformatter(std::string& input, char const* exp, char const* format) {
0029     std::regex regexp(exp, std::regex::egrep);
0030     while (std::regex_match(input, regexp)) {
0031       std::string newstring = std::regex_replace(input, regexp, format);
0032       input.swap(newstring);
0033     }
0034   }
0035 
0036   void removeParameter(std::string& demangledName, std::string const& toRemove) {
0037     std::string::size_type const asize = toRemove.size();
0038     char const* const delimiters = "<>";
0039     std::string::size_type index = std::string::npos;
0040     while ((index = demangledName.find(toRemove)) != std::string::npos) {
0041       int depth = 1;
0042       std::string::size_type inx = index + asize;
0043       while ((inx = demangledName.find_first_of(delimiters, inx)) != std::string::npos) {
0044         if (demangledName[inx] == '<') {
0045           ++depth;
0046         } else {
0047           --depth;
0048           if (depth == 0) {
0049             demangledName.erase(index, inx + 1 - index);
0050             if (demangledName[index] == ' ' && (index == 0 || demangledName[index - 1] != '>')) {
0051               demangledName.erase(index, 1);
0052             }
0053             break;
0054           }
0055         }
0056         ++inx;
0057       }
0058     }
0059   }
0060 
0061   void constBeforeIdentifier(std::string& demangledName) {
0062     std::string const toBeMoved(" const");
0063     std::string::size_type const asize = toBeMoved.size();
0064     std::string::size_type index = std::string::npos;
0065     while ((index = demangledName.find(toBeMoved)) != std::string::npos) {
0066       demangledName.erase(index, asize);
0067       int depth = 0;
0068       for (std::string::size_type inx = index - 1; inx > 0; --inx) {
0069         char const c = demangledName[inx];
0070         if (c == '>') {
0071           ++depth;
0072         } else if (depth > 0) {
0073           if (c == '<')
0074             --depth;
0075         } else if (c == '<' || c == ',') {
0076           demangledName.insert(inx + 1, "const ");
0077           break;
0078         }
0079       }
0080     }
0081   }
0082 }  // namespace
0083 
0084 namespace edm {
0085   void replaceString(std::string& demangledName, std::string const& from, std::string const& to) {
0086     // from must not be a substring of to.
0087     std::string::size_type length = from.size();
0088     std::string::size_type pos = 0;
0089     while ((pos = demangledName.find(from, pos)) != std::string::npos) {
0090       demangledName.replace(pos, length, to);
0091     }
0092   }
0093 
0094   std::string typeDemangle(char const* mangledName) {
0095     int status = 0;
0096     size_t* const nullSize = nullptr;
0097     char* const null = nullptr;
0098 
0099     // The demangled C style string is allocated with malloc, so it must be deleted with free().
0100     char* demangled = abi::__cxa_demangle(mangledName, null, nullSize, &status);
0101     if (status != 0) {
0102       throw cms::Exception("Demangling error") << " '" << mangledName << "'\n";
0103     }
0104     std::string demangledName(demangled);
0105     free(demangled);
0106     // We must use the same conventions previously used by REFLEX.
0107     // The order of these is important.
0108     // No space after comma
0109     replaceString(demangledName, ", ", ",");
0110     // No space before opening square bracket
0111     replaceString(demangledName, " [", "[");
0112     // clang libc++ uses __1:: namespace
0113     replaceString(demangledName, "std::__1::", "std::");
0114     // new gcc abi uses __cxx11:: namespace
0115     replaceString(demangledName, "std::__cxx11::", "std::");
0116     // Strip default allocator
0117     std::string const allocator(",std::allocator<");
0118     removeParameter(demangledName, allocator);
0119     // Strip default comparator
0120     std::string const comparator(",std::less<");
0121     removeParameter(demangledName, comparator);
0122     // Put const qualifier before identifier.
0123     constBeforeIdentifier(demangledName);
0124     // No two consecutive '>'
0125     replaceString(demangledName, ">>", "> >");
0126     // No u or l qualifiers for integers.
0127     reformatter(demangledName, "(.*[<,][0-9]+)[ul]l*([,>].*)", "$1$2");
0128     // For ROOT 6 and beyond, replace 'unsigned long long' with 'ULong64_t'
0129     replaceString(demangledName, "unsigned long long", "ULong64_t");
0130     // For ROOT 6 and beyond, replace 'long long' with 'Long64_t'
0131     replaceString(demangledName, "long long", "Long64_t");
0132     return demangledName;
0133   }
0134 }  // namespace edm