// Make sure all dependent defines exist and have a valid value #pragma warning(disable: 4702) // unreachable code #pragma warning(disable: 4706) // assignment within conditional expression #ifndef NO_COMPILER_NAMES #define NO_COMPILER_NAMES 0 #endif #ifndef VERS_32BIT #define VERS_32BIT 1 #endif #if defined _CRTBLD && !defined _VCRT_BUILD #define _VCRT_BUILD #endif #ifndef PACK_SIZE #ifdef _VCRT_BUILD #define PACK_SIZE 8 #elif !VERS_32BIT #define PACK_SIZE 2 #elif defined(_X86_) #define PACK_SIZE 4 #else #define PACK_SIZE 8 #endif #endif // Check for version inconsistancies, and setup version flags #ifdef VERS_BSC #undef NO_COMPILER_NAMES #define NO_COMPILER_NAMES 1 #pragma inline_depth ( 3 ) #pragma check_stack ( off ) #else #pragma inline_depth ( 3 ) #pragma check_stack ( off ) #endif #define PURE = 0 #ifndef CC_COR #define CC_COR 1 #endif #include "undname.hxx" #if !defined(DASSERT) #if !defined(_VCRT_BUILD) && defined(_DEBUG) #include #define DASSERT(x) assert(x) #else #define DASSERT(x) #endif #else // This is an FE build; DASSERT is defined properly #endif #include #ifdef _VCRT_BUILD #include #include #include #endif #include #ifndef _countof #define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0])) #endif #include #include "utf8.h" #pragma warning(disable:4291) // No matching operator delete static unsigned int und_strlen(pcchar_t); static void und_memcpy(_Out_bytecap_(len) pchar_t dst, pcchar_t src, unsigned int len); static unsigned int und_strncmp(pcchar_t, pcchar_t, unsigned int); class DName; class DNameNode; class Replicator; class _HeapManager; class UnDecorator; // A 4K byte block, not including the header. That matches LIMIT_ID_LENGTH // in the frontend. const unsigned int memBlockSize = 4096; // Dev10 bug 662979 // undname will be pullled into libcmt.lib. Prefix with underscore to prevent potential conflict with user code. class _HeapManager { private: Alloc_t pOpNew; Free_t pOpDelete; struct Block { Block * next; char memBlock[memBlockSize]; Block() { next = 0; } }; Block * head; Block * tail; size_t blockLeft; public: void Constructor(Alloc_t pAlloc, Free_t pFree) { pOpNew = pAlloc; pOpDelete = pFree; blockLeft = 0; head = 0; tail = 0; } void * getMemory(size_t, int); void Destructor(void) { if (pOpDelete != 0) while (tail = head) { head = tail->next; (*pOpDelete)(tail); } } #define gnew new(heap,0) #define rnew new(heap,1) }; void * operator new (size_t, _HeapManager &, int = 0); static _HeapManager heap; // The MS Token table enum Tokens { #if !VERS_32BIT TOK_near, TOK_nearSp, TOK_nearP, TOK_far, TOK_farSp, TOK_farP, TOK_huge, TOK_hugeSp, TOK_hugeP, #endif TOK_basedLp, TOK_cdecl, TOK_pascal, TOK_stdcall, TOK_thiscall, TOK_fastcall, TOK_vectorcall, TOK_cocall, TOK_eabi, TOK_swift_1, TOK_swift_2, TOK_ptr64, TOK_restrict, TOK_unaligned, #if !VERS_32BIT TOK_interrupt, TOK_saveregs, TOK_self, TOK_segment, TOK_segnameLpQ, #endif #if CC_RESTRICTION_SPEC TOK_restrictSpecLp, #endif // CC_RESTRICTION_SPEC TOK__last }; static constexpr pcchar_t tokenTable[] = { #if !VERS_32BIT "__near", // TOK_near "__near ", // TOK_nearSp "__near*", // TOK_nearP "__far", // TOK_far "__far ", // TOK_farSp "__far*", // TOK_farP "__huge", // TOK_huge "__huge ", // TOK_hugeSp "__huge*", // TOK_hugeP #endif "__based(", // TOK_basedLp "__cdecl", // TOK_cdecl "__pascal", // TOK_pascal "__stdcall", // TOK_stdcall "__thiscall", // TOK_thiscall "__fastcall", // TOK_fastcall "__vectorcall", // TOK_vectorcall "__clrcall", // TOK_cocall "__eabi", // TOK_eabi "__swift_1", // TOK_swift_1 "__swift_2", // TOK_swift_2 "__ptr64", // TOK_ptr64 "__restrict", // TOK_restrict "__unaligned", // TOK_unaligned #if !VERS_32BIT "__interrupt", // TOK_interrupt "__saveregs", // TOK_saveregs "__self", // TOK_self "__segment", // TOK_segment "__segname(\"", // TOK_segnameLpQ #endif #if CC_RESTRICTION_SPEC "restrict(", // TOK_restrict_spec #endif // CC_RESTRICTION_SPEC "" }; // The operator mapping table static constexpr pcchar_t nameTable[] = { " new", " delete", "=", ">>", "<<", "!", "==", "!=", "[]", "operator", "->", "*", "++", "--", "-", "+", "&", "->*", "/", "%", "<", "<=", ">", ">=", ",", "()", "~", "^", "|", "&&", "||", "*=", "+=", "-=", "/=", "%=", ">>=", "<<=", "&=", "|=", "^=", #if ( !NO_COMPILER_NAMES ) "`vftable'", "`vbtable'", "`vcall'", "`typeof'", "`local static guard'", "`string'", "`vbase destructor'", "`vector deleting destructor'", "`default constructor closure'", "`scalar deleting destructor'", "`vector constructor iterator'", "`vector destructor iterator'", "`vector vbase constructor iterator'", "`virtual displacement map'", "`eh vector constructor iterator'", "`eh vector destructor iterator'", "`eh vector vbase constructor iterator'", "`copy constructor closure'", "`udt returning'", "`EH", //eh initialized struct "`RTTI", //rtti initialized struct "`local vftable'", "`local vftable constructor closure'", #endif // !NO_COMPILER_NAMES " new[]", " delete[]", #if ( !NO_COMPILER_NAMES ) "`omni callsig'", "`placement delete closure'", "`placement delete[] closure'", "`managed vector constructor iterator'", "`managed vector destructor iterator'", "`eh vector copy constructor iterator'", "`eh vector vbase copy constructor iterator'", "`dynamic initializer for '", "`dynamic atexit destructor for '", "`vector copy constructor iterator'", "`vector vbase copy constructor iterator'", "`managed vector copy constructor iterator'", "`local static thread guard'", #endif "operator \"\" ", "operator co_await", "" }; static constexpr pcchar_t ehTable[] = { " Ptr to Member Data'", " Catchable Type'", " Catchable Type Array'", " ThrowInfo'", }; static constexpr pcchar_t rttiTable[] = { " Type Descriptor'", " Base Class Descriptor at (", " Base Class Array'", " Class Hierarchy Descriptor'", " Complete Object Locator'", }; // ------------------------------------------------------------------------ // // DName // // A DName is the result of undecorating part of a decorated name. It has // three main parts: a string, a status, and some flags that are used to // communicate what kind of thing the string represents. The bulk of the work // of the undecorator is scanning the input and building the output string. // DName supports a wide variety of string operations via overloaded operators // to make the main algorithm as plain as possible. // // A DName can contain embedded DNames. This is used to generate a declarator // like "void #()" (where # is the embedded DName) and later set # to "__cdecl // foo" to build the full string "void __cdecl foo()". // // Once a the DName::length method has been called, you should no longer // assign to or append to any of the embedded DNames. The protocol is: // // 1. Build the DName // 2. Get the length // 3. Get the text using getString(pchar_t, int); // // The following 'enum' should really be nested inside 'class DName', but to // make the code compile better with Glockenspiel, I have extracted it enum DNameStatus { DN_valid, // good result DN_truncated, // ran out of input string or subcomponent DN_invalid, // unusable input, not a valid decorated name DN_error // internal error }; class DName { public: DName(); DName(char); DName(const DName &); // Shallow copy DName(pcchar_t); DName(pcchar_t&, char); DName(DNameStatus); DName(DName *); DName(unsigned __int64); DName(__int64); int isValid() const; int isEmpty() const; DNameStatus status() const; void clearStatus(); DName& setPtrRef(); int isPtrRef() const; int isUDC() const; void setIsUDC(); int isUDTThunk() const; void setIsUDTThunk(); int isArray() const; void setIsArray(); int isNoTE() const; void setIsNoTE(); int isPinPtr() const; void setIsPinPtr(); int isComArray() const; void setIsComArray(); int isVCallThunk() const; void setIsVCallThunk(); int length() const; // Returns the last character, or '\0' if the DName represents an empty // string. char getLastChar() const; // Top level getString. Allocates a buffer if none provided. // NUL-terminates the buffer. pchar_t getString(_Inout_z_cap_(max) pchar_t buf, int max) const; // Internal getString fills in characters at 'buf' and returns a // pointer to the position of the next character in buf. 'end' points // after the last character in the buffer. pchar_t getString(_In_z_ pchar_t buf, _In_ pchar_t end) const; #ifdef _DEBUG pchar_t dbGetString() const; #endif DName operator + (pcchar_t) const; DName operator + (const DName &) const; DName operator + (char) const; DName operator + (DName *) const; DName operator + (DNameStatus) const; DName & operator += (char); DName & operator += (pcchar_t); DName & operator += (DName *); DName & operator += (DNameStatus); DName & operator += (const DName &); DName & operator |= (const DName &); DName & operator = (pcchar_t); DName & operator = (const DName &); DName & operator = (char); DName & operator = (DName *); DName & operator = (DNameStatus); // Friends : friend DName operator + (char, const DName &); friend DName operator + (pcchar_t, const DName &); friend DName operator + (DNameStatus, const DName &); private: const DNameNode * node; union { unsigned int value; struct { DNameStatus stat : 8; unsigned int isIndir : 1; unsigned int isAUDC : 1; unsigned int isAUDTThunk : 1; unsigned int isArrayType : 1; unsigned int NoTE : 1; unsigned int pinPtr : 1; unsigned int comArray : 1; unsigned int vcallThunk : 1; }; }; void append(const DNameNode *newRight); void doPchar(pcchar_t, int); }; class Replicator { private: // Declare, in order to suppress automatic generation void operator = (const Replicator&); int index; DName * dNameBuffer[10]; public: Replicator(); int isFull() const; Replicator & operator += (const DName &); DName operator [] (int) const; }; class UnDecorator { private: // Declare, in order to suppress automatic generation void operator = (const UnDecorator&); Replicator ArgList; static Replicator * pArgList; Replicator ZNameList; static Replicator * pZNameList; static Replicator * pTemplateArgList; static pcchar_t gName; static pcchar_t name; static unsigned long disableFlags; static bool fExplicitTemplateParams; static bool fGetTemplateArgumentList; static DName getDecoratedName(void); static DName getSymbolName(void); static DName getZName(bool fUpdateCachedNames, bool fAllowEmptyName = false); static DName getOperatorName(bool fIsTemplate, bool *pfReadTemplateArguments); static DName getScope(void); static DName getScopedName(void); static DName getSignedDimension(void); static DName getDimension(bool fSigned = false); static int getNumberOfDimensions(void); static DName getTemplateName(bool); static DName getTemplateArgumentList(void); static DName getTemplateConstant(void); static DName composeDeclaration(const DName &); static int getTypeEncoding(void); static DName getBasedType(void); static DName getECSUName(void); static DName getEnumType(void); static DName getCallingConvention(void); static DName getReturnType(DName * = 0); static DName getDataType(DName *); static DName getPrimaryDataType(const DName &); static DName getDataIndirectType(const DName &, const char*, const DName &, int = FALSE); static DName getExtendedDataIndirectType(const char*& prType, bool& fIsPinPtr, int thisFlag); static DName getDataIndirectType(); static DName getBasicDataType(const DName &); static DName getECSUDataType(void); static DName getPtrRefType(const DName &, const DName &, const char*); static DName getPtrRefDataType(const DName &, int); static DName getArrayType(const DName&); static DName getFunctionIndirectType(const DName & superType); static DName getArgumentTypes(void); static DName getArgumentList(void); static DName getThrowTypes(void); static DName getNoexcept(); #if CC_RESTRICTION_SPEC static DName getRestrictionSpec(void); static DName getDispatchTarget(void); #endif // CC_RESTRICTION_SPEC static DName getLexicalFrame(void); static DName getStorageConvention(void); static DName getThisType(void); static DName getPointerType(const DName &, const DName &); static DName getPointerTypeArray(const DName &, const DName &); static DName getReferenceType(const DName &, const DName &, const char*); static DName getExternalDataType(const DName &); static DName getSegmentName(void); #if ( !NO_COMPILER_NAMES ) static DName getDisplacement(void); static DName getCallIndex(void); static DName getGuardNumber(void); static DName getVfTableType(const DName &); static DName getVbTableType(const DName &); static DName getVdispMapType(const DName &); static DName getVCallThunkType(void); #endif // !NO_COMPILER_NAMES static DName getStringEncoding(_In_z_ const char *prefix, int wantBody); static DName parseDecoratedName(void); static GetParameter_t m_pGetParameter; static unsigned long m_CHPENameOffset; static unsigned long m_recursionLevel; public: UnDecorator(pcchar_t, GetParameter_t, unsigned long); static int doUnderScore(); static int doMSKeywords(); static int doPtr64(); static int doFunctionReturns(); static int doAllocationModel(); static int doAllocationLanguage(); #if 0 static int doMSThisType(); static int doCVThisType(); #endif static int doThisTypes(); static int doAccessSpecifiers(); static int doThrowTypes(); static int doMemberTypes(); static int doReturnUDTModel(); static int do32BitNear(); static int doNameOnly(); static int doTypeOnly(); static int haveTemplateParameters(); static int doEcsu(); static int doNoIdentCharCheck(); static int doEllipsis(); #if CC_RESTRICTION_SPEC static int doRestrictionSpec(); #endif // CC_RESTRICTION_SPEC static pcchar_t UScore(Tokens); pchar_t getUndecoratedName(_Out_opt_z_cap_(maxStringLength) pchar_t, int maxStringLength); pchar_t getCHPEName(_Out_opt_z_cap_(maxStringLength) pchar_t, int maxStringLength); }; Replicator * UnDecorator::pArgList; Replicator * UnDecorator::pZNameList; Replicator * UnDecorator::pTemplateArgList; pcchar_t UnDecorator::gName; pcchar_t UnDecorator::name; unsigned long UnDecorator::disableFlags; GetParameter_t UnDecorator::m_pGetParameter; bool UnDecorator::fExplicitTemplateParams; bool UnDecorator::fGetTemplateArgumentList; unsigned long UnDecorator::m_CHPENameOffset; unsigned long UnDecorator::m_recursionLevel; pchar_t __cdecl unDNameGenerateCHPE ( _Out_opt_z_cap_(maxStringLength) pchar_t outputString, pcchar_t name, int maxStringLength, Alloc_t pAlloc, Free_t pFree, unsigned long disableFlags ) { if (!(pAlloc)) return 0; pchar_t chpeName = nullptr; heap.Constructor(pAlloc, pFree); UnDecorator unDecorate(name, nullptr, disableFlags); chpeName = unDecorate.getCHPEName(outputString, maxStringLength); heap.Destructor(); return chpeName; } pchar_t __UNDNAME_IMP __cdecl __UNDNAME_NAME( _Out_opt_z_cap_(maxStringLength) pchar_t outputString, pcchar_t name, int maxStringLength, // Note, COMMA is leading following optional arguments Alloc_t pAlloc, Free_t pFree, unsigned short disableFlags ) /* * This function will undecorate a name, returning the string corresponding to * the C++ declaration needed to produce the name. Its has a similar interface * to 'strncpy'. * * If the target string 'outputString' is specified to be NULL, a string of * suitable length will be allocated and its address returned. If the returned * string is allocated by 'unDName', then it is the programmers responsibility * to deallocate it. It will have been allocated on the far heap. * * If the target string is not NULL, then the parameter 'maxStringLength' will * specify the maximum number of characters which may be placed in the string. * In this case, the returned value is the same as 'outputString'. * * Both the input parameter 'name' and the returned string are NULL terminated * strings of characters. * * If the returned value is NULL, it indicates that the undecorator ran out of * memory, or an internal error occurred, and was unable to complete its task. */ { return __UNDNAME_NAME_EX(outputString, name, maxStringLength, pAlloc, pFree, nullptr, disableFlags); } pchar_t __UNDNAME_IMP __cdecl __UNDNAME_NAME_EX( _Out_opt_z_cap_(maxStringLength) pchar_t outputString, pcchar_t name, int maxStringLength, // Note, COMMA is leading following optional arguments Alloc_t pAlloc, Free_t pFree, GetParameter_t pGetParameter, unsigned long disableFlags ) /* * This function will undecorate a name, returning the string corresponding to * the C++ declaration needed to produce the name. Its has a similar interface * to 'strncpy'. * * If the target string 'outputString' is specified to be NULL, a string of * suitable length will be allocated and its address returned. If the returned * string is allocated by 'unDName', then it is the programmers responsibility * to deallocate it. It will have been allocated on the far heap. * * If the target string is not NULL, then the parameter 'maxStringLength' will * specify the maximum number of characters which may be placed in the string. * In this case, the returned value is the same as 'outputString'. * * Both the input parameter 'name' and the returned string are NULL terminated * strings of characters. * * If the returned value is NULL, it indicates that the undecorator ran out of * memory, or an internal error occurred, and was unable to complete its task. */ { // Must have an allocator and a deallocator (and we MUST trust them) if (!(pAlloc)) return 0; pchar_t unDecoratedName = nullptr; #ifdef _VCRT_BUILD __vcrt_lock(__vcrt_undname_lock); __try { #endif heap.Constructor(pAlloc, pFree); // Create the undecorator object, and get the result UnDecorator unDecorate(name, pGetParameter, disableFlags); unDecoratedName = unDecorate.getUndecoratedName(outputString, maxStringLength); // Destruct the heap (would use a destructor, but that causes DLL problems) heap.Destructor(); #ifdef _VCRT_BUILD } __finally { __vcrt_unlock(__vcrt_undname_lock); } #endif // And return the composed name return unDecoratedName; } // End of FUNCTION "unDName" // The 'UnDecorator' member functions inline UnDecorator::UnDecorator( pcchar_t dName, GetParameter_t pGetParameter, unsigned long disable ) { name = dName; gName = name; pZNameList = &ZNameList; pArgList = &ArgList; disableFlags = disable; m_pGetParameter = pGetParameter; fExplicitTemplateParams = false; m_CHPENameOffset = 0; m_recursionLevel = 0; } // End of "UnDecorator" CONSTRUCTOR '()' DName UnDecorator::parseDecoratedName(void) { DName result; // Find out if the name is a decorated name or not. Could be a reserved // CodeView variant of a decorated name if (name) { if ((*name == '?') && (name[1] == '@')) { #if ( !NO_COMPILER_NAMES ) gName += 2; result = "CV: " + getDecoratedName(); #else // elif NO_COMPILER_NAMES result = DN_invalid; #endif // NO_COMPILER_NAMES } // End of IF then else if ((*name == '?') && (name[1] == '$')) { result = getTemplateName(false); if ((result.status() == DN_invalid) || (!doNameOnly() && *gName)) { // // What harm could there be to try again ? // Repro: // ?$S1@?1??VTFromRegType@CRegParser@ATL@@KAHPBGAAG@Z@4IA // ---> unsigned int `protected: static int __cdecl ATL::CRegParser::VTFromRegType(unsigned short const *,unsigned short &)'::`2'::$S1 // // This is a compiler generated symbol for a local static array init. // gName = name; result = getDecoratedName(); } } else if ((name[0] == '?') && (name[1] == '?') && (name[2] == '@')) { // A name that starts with "??@" is a truncated decorated name so do not attempt to undecorate it result = DN_invalid; } else { result = getDecoratedName(); } } return result; } inline pchar_t UnDecorator::getUndecoratedName ( _Out_opt_z_cap_(maxStringLength) pchar_t outputString, int maxStringLength ) { DName unDName; DName result = parseDecoratedName(); // If the name was not a valid name, then make the name the same as the original // It is also invalid if there are any remaining characters in the name (except when // we're giving the name only) if (result.status() == DN_error) return 0; else if((result.status() == DN_invalid) || (!doNameOnly() && *gName)) unDName = name; // Return the original name else unDName = result; // Construct the return string if (!outputString) { maxStringLength = unDName.length() + 1; outputString = rnew char[maxStringLength]; } // End of IF if (outputString) { unDName.getString(outputString, maxStringLength); // strip extra whitespace out of name pchar_t pRead = outputString; pchar_t pWrite = pRead; while (*pRead) { if (*pRead == ' ') { pRead++; *pWrite++ = ' '; while (*pRead == ' ') { pRead++; } } else *pWrite++ = *pRead++; } *pWrite = *pRead; } // Return the result return outputString; } // End of "UnDecorator" getUndecoratedName inline pchar_t UnDecorator::getCHPEName( _Out_opt_z_cap_(maxStringLength) pchar_t outputString, int maxStringLength ) { DName result = parseDecoratedName(); if (result.status() != DN_valid) { return nullptr; } if (m_CHPENameOffset == 0) { return nullptr; } // compute final string length size_t len = strlen(name); if (m_CHPENameOffset >= len) { DASSERT(FALSE && "Invalid CHPE name offset"); return nullptr; } const char chpeMarker[] = "$$h"; const size_t chpeMarkerSize = strlen(chpeMarker); // Check if the name is already a CHPE name. if (strncmp(name + m_CHPENameOffset, chpeMarker, chpeMarkerSize) == 0) { return nullptr; } size_t finalLen = len + chpeMarkerSize + sizeof('\0'); if (finalLen < len) { return nullptr; } if (outputString) { if (finalLen >= (size_t)maxStringLength) { return nullptr; } } else { outputString = rnew char[finalLen]; if (!outputString) { return nullptr; } } memcpy(outputString, name, m_CHPENameOffset); memcpy(outputString + m_CHPENameOffset, chpeMarker, chpeMarkerSize); memcpy(outputString + m_CHPENameOffset + chpeMarkerSize, name + m_CHPENameOffset, len - m_CHPENameOffset + sizeof('\0')); return outputString; } #ifdef _DEBUG pchar_t DName::dbGetString() const { static char buf[80]; getString(buf, 80); return buf; } #endif DName UnDecorator::getDecoratedName(void) { // Setup a C++ object that will count recursive invocations of this // function. struct TrackRecursion { TrackRecursion() { m_recursionLevel += 1; } ~TrackRecursion() { m_recursionLevel -= 1; } } trackRecursion; // Ensure that it is intended to be a decorated name if (doTypeOnly()) { // Disable the type-only flag, so that if we get here recursively, eg. // in a template tag, we do full name undecoration. disableFlags &= ~UNDNAME_TYPE_ONLY; // If we're decoding just a type, process it as the type for an abstract // declarator, by giving an empty symbol name. DName result = getDataType(NULL); disableFlags |= UNDNAME_TYPE_ONLY; return result; } else if(*gName == '?') { // Extract the basic symbol name gName++; // Advance the original name pointer // What!?!? we have a name that starts with '???' how is this possible? // Easy: consider code like the following: // // int f(); // // int g = f(); // // This will cause the compiler to generate am extern "C" file-scope static // initialization function with the name '??__Eg@@YAXXZ' // // Now: let's say that we compile with file with /clr: as the CLR cannot handle // file scope statics the compiler makes them all look like members of an anonymous // namespace. So the compiler will try to decorate then name again even though we // have already marked it as extern "C". The new name it will generate will be: // '???__Eg@@YMXXZ@?A0x2109f7d3@@$$FYMXXZ' // // So how should we undecorate this? Well unless you want a really weird looking // name the best way is to forget about the encoding added because of the CLR as // just undecorate the orginial name. if ((gName[0] == '?') && (gName[1] == '?')) { // Skip the first '?' and restart the undecoration process. DName result = getDecoratedName(); // We have undecorated the original name ... skip whatever else was added // to keep the CLR happy while (*gName != '\0') { ++gName; } return result; } DName symbolName = getSymbolName(); int udcSeen = symbolName.isUDC(); int vcallThunkSeen = symbolName.isVCallThunk(); // Abort if the symbol name is invalid if (!symbolName.isValid()) return symbolName; // Extract, and prefix the scope qualifiers if (*gName && (*gName != '@')) { DName scope = getScope(); if (!scope.isEmpty()) if (fExplicitTemplateParams) { fExplicitTemplateParams = false; symbolName = symbolName + scope; if (*gName != '@') { scope = getScope(); symbolName = scope + "::" + symbolName; } } else { symbolName = scope + "::" + symbolName; } } if (udcSeen) symbolName.setIsUDC(); if (vcallThunkSeen) { symbolName.setIsVCallThunk(); } // Now compose declaration if (symbolName.isEmpty() || symbolName.isNoTE()) { return symbolName; } else if(!*gName || (*gName == '@')) { if (*gName) gName++; if (doNameOnly() && !udcSeen && !symbolName.isVCallThunk()) { // Eat the rest of the dname, in case this is a recursive invocation, // such as for a template argument. (void)composeDeclaration(DName()); return symbolName; } else { return composeDeclaration(symbolName); } } // End of else if then else return DN_invalid; } // End of IF then else if(*gName) return DN_invalid; else return DN_truncated; } // End of "UnDecorator" FUNCTION "getDecoratedName" inline DName UnDecorator::getSymbolName() { if (gName[0] == '?') { if (gName[1] == '$') { return getTemplateName(true); } else { gName += 1; return getOperatorName(false, NULL); } } else { return getZName(true); } } DName UnDecorator::getZName(bool fUpdateCachedNames, bool fAllowEmptyName) { int zNameIndex = *gName - '0'; // Handle 'zname-replicators', otherwise an actual name if ((zNameIndex >= 0) && (zNameIndex <= 9)) { gName++; // Skip past the replicator // And return the indexed name return (*pZNameList)[zNameIndex]; } // End of IF then else { DName zName; if (*gName == '?') { zName = getTemplateName(false); if (*gName++ != '@') zName = *--gName ? DN_invalid : DN_truncated; } else { #define TEMPLATE_PARAMETER "template-parameter-" #define TEMPLATE_PARAMETER_LEN 19 #define GENERIC_TYPE "generic-type-" #define GENERIC_TYPE_LEN 13 pcchar_t genericType; if (und_strncmp(gName, TEMPLATE_PARAMETER, TEMPLATE_PARAMETER_LEN) == 0) { genericType = TEMPLATE_PARAMETER; gName += TEMPLATE_PARAMETER_LEN; } else if (und_strncmp(gName, GENERIC_TYPE, GENERIC_TYPE_LEN) == 0) { genericType = GENERIC_TYPE; gName += GENERIC_TYPE_LEN; } else { genericType = NULL; } if (genericType) { DName dimension = getSignedDimension(); if (haveTemplateParameters() && (m_pGetParameter != nullptr)) { char buffer[16]; dimension.getString(buffer, 16); char *str = (*m_pGetParameter)(atol(buffer)); if (str != NULL) { zName = str; } else { zName = "`"; zName += genericType + dimension + "'"; } } else { zName = "`"; zName += genericType + dimension + "'"; } } else if (fAllowEmptyName && *gName == '@') { // Empty zname is used in old-style template function decorated names zName = DName(); gName += 1; } else { // Extract the 'zname' to the terminator zName = DName(gName, '@'); // This constructor updates 'name' } } // Add it to the current list of 'zname's if (fUpdateCachedNames && !pZNameList->isFull()) *pZNameList += zName; // And return the symbol name return zName; } // End of IF else } // End of "UnDecorator" FUNCTION "getZName" inline DName UnDecorator::getOperatorName(bool fIsTemplate, bool *pfReadTemplateArguments) { DName operatorName; DName tmpName; int udcSeen = FALSE; int index = 0; // So what type of operator is it ? switch (*gName++) { case 0: gName--; // End of string, better back-track return DN_truncated; case OC_ctor: case OC_dtor: // // The constructor and destructor are special: // Their operator name is the name of their first enclosing scope, which // will always be a tag, which may be a template specialization! // { // // Is this a specialization of a member function template? If it is // then we will actually have the template arguments between the "name" // of the operator and the scope: so we need to read the template // arguments before we try to read the name of the class // DName templateArguments; if (fIsTemplate) { templateArguments += '<' + getTemplateArgumentList(); if (templateArguments.getLastChar() == '>') { templateArguments += ' '; } templateArguments += '>'; if (pfReadTemplateArguments != NULL) { *pfReadTemplateArguments = true; } // // It is possible that we only want to decode the template // arguments -- this happens when want to create a name like // mf to use in meta-data // if (*gName == '\0') { return templateArguments; } gName += 1; } // // Use a temporary. Don't want to advance the name pointer // pcchar_t pName = gName; operatorName = getZName(false); gName = pName; // Undo our lookahead if (!operatorName.isEmpty() && (gName[-1] == OC_dtor)) operatorName = '~' + operatorName; // // Append the template argumentsa (if there are any) // if (!templateArguments.isEmpty()) { operatorName += templateArguments; } return operatorName; } // End of CASE 'OC_ctor,OC_dtor' break; case OC_new: case OC_delete: case OC_assign: case OC_rshift: case OC_lshift: case OC_not: case OC_equal: case OC_unequal: operatorName = nameTable[gName[-1] - OC_new]; break; case OC_udc: udcSeen = TRUE; // No break case OC_index: case OC_pointer: case OC_star: case OC_incr: case OC_decr: case OC_minus: case OC_plus: case OC_amper: case OC_ptrmem: case OC_divide: case OC_modulo: case OC_less: case OC_leq: case OC_greater: case OC_geq: case OC_comma: case OC_call: case OC_compl: case OC_xor: case OC_or: case OC_land: case OC_lor: case OC_asmul: case OC_asadd: case OC_assub: // Regular operators from the first group operatorName = nameTable[gName[-1] - OC_index + (OC_unequal - OC_new + 1)]; break; case '_': switch (*gName++) { case 0: gName--; // End of string, better back-track return DN_truncated; case OC_asdiv: case OC_asmod: case OC_asrshift: case OC_aslshift: case OC_asand: case OC_asor: case OC_asxor: // Regular operators from the extended group operatorName = nameTable[gName[-1] - OC_asdiv + (OC_assub - OC_index + 1) + (OC_unequal - OC_new + 1)]; break; #if ( !NO_COMPILER_NAMES ) case OC_vftable: case OC_vbtable: return nameTable[gName[-1] - OC_asdiv + (OC_assub - OC_index + 1) + (OC_unequal - OC_new + 1)]; break; case OC_vcall: { DName result = nameTable[gName[-1] - OC_asdiv + (OC_assub - OC_index + 1) + (OC_unequal - OC_new + 1)]; result.setIsVCallThunk(); return result; } break; case OC_string: { DName result = getStringEncoding("`string'", TRUE); result.setIsNoTE(); return result; } case OC_metatype: case OC_guard: case OC_vbdtor: case OC_vdeldtor: case OC_defctor: case OC_sdeldtor: case OC_vctor: case OC_vdtor: case OC_vallctor: case OC_vdispmap: case OC_ehvctor: case OC_ehvdtor: case OC_ehvctorvb: case OC_copyctorclosure: case OC_locvfctorclosure: case OC_locvftable: // Special purpose names case OC_placementDeleteClosure: case OC_placementArrayDeleteClosure: return nameTable[gName[-1] - OC_metatype + (OC_vcall - OC_asdiv + 1) + (OC_assub - OC_index + 1) + (OC_unequal - OC_new + 1)]; case OC_udtthunk: operatorName = nameTable[gName[-1] - OC_metatype + (OC_vcall - OC_asdiv + 1) + (OC_assub - OC_index + 1) + (OC_unequal - OC_new + 1)]; tmpName = getOperatorName(false, NULL); if (!tmpName.isEmpty() && tmpName.isUDTThunk()) return DN_invalid; return operatorName + tmpName; break; case OC_eh_init: break; case OC_rtti_init: operatorName = nameTable[gName[-1] - OC_metatype + (OC_vcall - OC_asdiv + 1) + (OC_assub - OC_index + 1) + (OC_unequal - OC_new + 1)]; if (!gName[0]) return operatorName + DN_truncated; index = gName[0] - OC_rtti_TD; if (index < 0 || index >= _countof(rttiTable)) return DN_invalid; tmpName = rttiTable[index]; switch (*gName++) { case OC_rtti_TD: { DName result = getDataType(NULL); return result + ' ' + operatorName + tmpName; } break; case OC_rtti_BCD: { DName result = operatorName + tmpName; result += getSignedDimension() + ','; result += getSignedDimension() + ','; result += getSignedDimension() + ','; result += getDimension() + ')'; return result + '\''; } break; case OC_rtti_BCA: case OC_rtti_CHD: case OC_rtti_COL: return operatorName + tmpName; break; default: gName--; return DN_truncated; break; } break; #endif // !NO_COMPILER_NAMES case OC_arrayNew: case OC_arrayDelete: operatorName = nameTable[gName[-1] - OC_metatype + (OC_vcall - OC_asdiv + 1) + (OC_assub - OC_index + 1) + (OC_unequal - OC_new + 1) #if NO_COMPILER_NAMES - (OC_locvfctorclosure - OC_vftable + 1) // discount names not in table #endif ]; break; // Yet another level of nested encodings.... case '?': switch (*gName++) { case 0: gName--; // End of string, better back-track return DN_truncated; case OC_anonymousNamespace: // // Anonymous namespace (new-style) is a string encoding of the // machine name and the translation unit name. Since the remainder // of the name doesn't really fit the dname grammar, skip it. // There are two '@' markers in the name.... // { DName result = getStringEncoding("`anonymous namespace'", FALSE); result.setIsNoTE(); return result; } default: return DN_invalid; } break; // // A double extended operator // case '_': switch (*gName++) { case OC_man_vec_ctor: case OC_man_vec_dtor: case OC_ehvcctor: case OC_ehvcctorvb: case OC_vec_copy_ctor: case OC_vec_copy_ctor_vb: case OC_man_vec_copy_ctor: case OC_thread_guard: case OC_await: return nameTable[gName[-1] - OC_man_vec_ctor + (OC_placementArrayDeleteClosure - OC_metatype + 1) + (OC_vcall - OC_asdiv + 1) + (OC_assub - OC_index + 1) + (OC_unequal - OC_new + 1)]; case OC_staticinit: case OC_staticatexit: { DName result = nameTable[gName[-1] - OC_man_vec_ctor + (OC_placementArrayDeleteClosure - OC_metatype + 1) + (OC_vcall - OC_asdiv + 1) + (OC_assub - OC_index + 1) + (OC_unequal - OC_new + 1)]; // Is the 'name' after the operator decorated or not? How is this // possible? Well consider the following: // // int f() // // int g = f(); // // struct X { // static int s; // }; // // int X::s = f(); // // The name for the initializer for g is '??__Eg@@YAXXZ' while the // name for the initializer for X::s is '??__E?s@X@@2HA@@YAXXZ'. So // we either have a decorated name or a simple symbol name. Undecorate // the names appropriate. if (*gName == '?') { result += getDecoratedName(); // If the decorated name ends withe '@' skip it so that we are ready to process // the next section if (*gName == '@') { gName += 1; } } else { result += getSymbolName(); } result += "''"; return result; } break; case OC_udl: { DName result = nameTable[gName[-1] - OC_man_vec_ctor + (OC_placementArrayDeleteClosure - OC_metatype + 1) + (OC_vcall - OC_asdiv + 1) + (OC_assub - OC_index + 1) + (OC_unequal - OC_new + 1)]; DASSERT(*gName != '\"'); // This is to catch bugs when quotes in ""_suffix are encoded too. DASSERT(*gName != 0); // One can't have an empty UDL literal operator. This happens when "" leaks into name, but undname.exe does not consider " as a symbol valid in mangled name while (*gName != '\0' && *gName != '@') { result += *gName++; } if (*gName == '@') { gName += 1; } return result; } break; default: return DN_invalid; } break; default: return DN_invalid; } // End of SWITCH break; default: return DN_invalid; } // End of SWITCH // This really is an operator name, so prefix it with 'operator' if (udcSeen) operatorName.setIsUDC(); else if(!operatorName.isEmpty()) operatorName = "operator" + operatorName; return operatorName; } // End of "UnDecorator" FUNCTION "getOperatorName" DName UnDecorator::getStringEncoding(_In_z_ const char *prefix, int /*unused*/) { DName result = prefix; // First @ comes right after operator code if (*gName++ != '@' || *gName++ != '_') { return DN_invalid; } // Skip the string kind gName++; // Get (& discard) the length getDimension(); // Get (& discart) the checksum getDimension(); while (*gName && *gName != '@') { // For now, we'll just skip it gName++; } if (!*gName) { gName--; return DN_truncated; } // Eat the terminating '@' gName++; return result; } DName UnDecorator::getScope(void) { DName scope; bool fNeedBracket = false; // Get the list of scopes while ((scope.status() == DN_valid) && *gName && (*gName != '@')) { // Insert the scope operator if not the first scope if (fExplicitTemplateParams && !fGetTemplateArgumentList) { return scope; } if (!scope.isEmpty()) { scope = "::" + scope; if (fNeedBracket) { scope = '[' + scope; fNeedBracket = false; } } // Determine what kind of scope it is if (*gName == '?') switch (*++gName) { case '?': if (gName[1] == '_' && gName[2] == '?') { // // Anonymous namespace name (new style) // gName++; scope = getOperatorName(false, NULL) + scope; // There should be a zname termination @... if (*gName == '@') { gName++; } } else scope = '`' + getDecoratedName() + '\'' + scope; break; case '$': // It's a template name, which is a kind of zname; back up // and handle like a zname. gName--; scope = getZName(true) + scope; break; case 'A': // // This is a new-new encoding for anonymous namespaces // // fall-through case '%': { // // It an anonymous namespace (old-style); // skip the (unreadable) name and instead insert // an appropriate string // DName namespaceName = DName(gName, '@'); scope = "`anonymous namespace'" + scope; if (!pZNameList->isFull()) { *pZNameList += namespaceName; } } break; case 'I': // // This is the interface whose method the class is // implementing // gName++; scope = getZName(true) + ']' + scope; fNeedBracket = true; break; case 'Q': // This is new style of enclosing any interface whose method the class is implementing { DName explicitScope; ++gName; do { DName scopeName = getZName(true); if (scopeName.status() == DN_valid) { if (!explicitScope.isEmpty()) { explicitScope = scopeName + "::" + explicitScope; } else { explicitScope = scopeName; } } else { explicitScope = DN_invalid; } } while ((explicitScope.status() == DN_valid) && (*gName != '@')); if (explicitScope.status() == DN_valid) { scope = '[' + explicitScope + ']'; ++gName; } else { scope = DN_invalid; } } break; default: scope = getLexicalFrame() + scope; break; } // End of SWITCH else scope = getZName(true) + scope; } // End of WHILE // Catch error conditions switch (*gName) { case 0: if (scope.isEmpty()) scope = DN_truncated; else scope = DName(DN_truncated) + "::" + scope; break; case '@': // '@' expected to end the scope list break; default: scope = DN_invalid; break; } // End of SWITCH // Return the composed scope return scope; } // End of "UnDecorator" FUNCTION "getScope" DName UnDecorator::getSignedDimension(void) { if (!*gName) return DN_truncated; else if(*gName == '?') { gName++; // skip the '?' return '-' + getDimension(); } else return getDimension(); } // End of "Undecorator" FUNCTION "getSignedDimension" DName UnDecorator::getDimension(bool fSigned) { const char* prefix = 0; if (*gName == TC_nontype_dummy) { prefix = "`non-type-template-parameter"; ++gName; } if (!*gName) return DN_truncated; else if((*gName >= '0') && (*gName <= '9')) return prefix ? (prefix + DName((unsigned __int64)(*gName++ - '0' + 1))) : DName((unsigned __int64)(*gName++ - '0' + 1)); else { unsigned __int64 dim = 0ui64; // Don't bother detecting overflow, it's not worth it while (*gName != '@') { if (!*gName) return DN_truncated; else if((*gName >= 'A') && (*gName <= 'P')) dim = (dim << 4) + (*gName - 'A'); else return DN_invalid; gName++; } // End of WHILE // Ensure integrity, and return if (*gName++ != '@') return DN_invalid; // Should never get here if (fSigned) { return prefix ? (prefix + DName((__int64)dim)) : DName((__int64)dim); } else { return prefix ? (prefix + DName(dim)) : dim; } } // End of else if else } // End of "UnDecorator" FUNCTION "getDimension" int UnDecorator::getNumberOfDimensions(void) { if (!*gName) return 0; else if((*gName >= '0') && (*gName <= '9')) return ((*gName++ - '0') + 1); else { int dim = 0; // Don't bother detecting overflow, it's not worth it while (*gName != '@') { if (!*gName) return 0; else if((*gName >= 'A') && (*gName <= 'P')) dim = (dim << 4) + (*gName - 'A'); else return -1; gName++; } // End of WHILE // Ensure integrity, and return if (*gName++ != '@') return -1; // Should never get here return dim; } // End of else if else } // End of "UnDecorator" FUNCTION "getNumberOfDimensions" DName UnDecorator::getTemplateName(bool fReadTerminator) { // // First make sure we're really looking at a template name // if (gName[0] != '?' || gName[1] != '$') return DN_invalid; gName += 2; // Skip the marker characters // // Stack the replicators, since template names are their own replicator scope: // Replicator * pSaveArgList = pArgList; Replicator * pSaveZNameList = pZNameList; Replicator * pSaveTemplateArgList = pTemplateArgList; Replicator localArgList, localZNameList, localTemplateArgList; pArgList = &localArgList; pZNameList = &localZNameList; pTemplateArgList = &localTemplateArgList; // // Crack the template name: // DName templateName; bool fReadTemplateArguments = false; if (*gName == '?') { gName += 1; templateName = getOperatorName(true, &fReadTemplateArguments); } else { templateName = getZName(true, true); } if (templateName.isEmpty()) { fExplicitTemplateParams = true; } // // If we haven't already read the template arguments then // now is the time to read them // if (!fReadTemplateArguments) { templateName += '<' + getTemplateArgumentList(); if (templateName.getLastChar() == '>') { templateName += ' '; } templateName += '>'; if (fReadTerminator && *gName) { gName += 1; } } // // Restore the previous replicators: // pArgList = pSaveArgList; pZNameList = pSaveZNameList; pTemplateArgList = pSaveTemplateArgList; // Return the completed 'template-name' return templateName; } // End of "UnDecorator" FUNCTION "getTemplateName" DName UnDecorator::getTemplateArgumentList(void) { bool first = true; DName aList; fGetTemplateArgumentList = true; while ((aList.status() == DN_valid) && *gName && (*gName != AT_endoflist)) { // Insert the argument list separator if not the first argument bool needComma = false; if (first) { first = false; } else { needComma = true; } // Get the individual argument type int argIndex = *gName - '0'; DName arg; bool havePackExpansion = false; // Handle 'template-argument-replicators', otherwise a new argument type if ((argIndex >= 0) && (argIndex <= 9)) { gName++; // Skip past the replicator // Argument to append to the argument list arg = (*pTemplateArgList)[argIndex]; } // End of IF then else { pcchar_t oldGName = gName; if ((*gName == PDT_extend) && (*(gName + 1) == PDT_extend)) { bool skipArgument = false; switch (*(gName + 2)) { case PDT_packExpansion: havePackExpansion = true; gName += 3; break; case PDT_placeHolder: gName += 3; break; case PDT_empty: case PDT_terminator: gName += 3; skipArgument = true; break; case PDT_extend: // We have a bug (in older builds of the compiler) in which 'empty' is encoded with an extra '$' if (*(gName + 3) == PDT_empty) { gName += 4; skipArgument = true; } break; default: break; } if (skipArgument) { continue; } } // // Extract the 'argument' type // if (*gName == BDT_void) { gName++; arg = "void"; } else if((*gName == '$') && (gName[1] != '$')) { gName++; arg = getTemplateConstant(); } else if(*gName == '?') { // // This is a template-parameter, i.e. we have a "specialization" of // X. so get the template-parameter-index and use a "generic" name // for this parameter // DName dimension = getSignedDimension(); if (haveTemplateParameters() && (m_pGetParameter != nullptr)) { char buffer[16]; dimension.getString(buffer, 16); char *str = (*m_pGetParameter)(atol(buffer)); if (str != NULL) { arg = str; } else { arg = "`template-parameter" + dimension + "'"; } } else { arg = "`template-parameter" + dimension + "'"; } } else { arg = getPrimaryDataType(DName()); } // Add it to the current list of 'template-argument's, if it is bigger than a one byte encoding if (((gName - oldGName) > 1) && !pTemplateArgList->isFull()) *pTemplateArgList += arg; } // End of IF else // Append to the argument list if (!arg.isEmpty()) { if (needComma) { aList += ','; } aList += arg; if (havePackExpansion) { aList += "..."; } } } // End of WHILE // Return the completed template argument list fGetTemplateArgumentList = false; return aList; } // End of "UnDecorator" FUNCTION "getTemplateArgumentList" using uint_t = unsigned int; union TPI_t { uint_t index_; // the old way struct { uint_t number_ : 12; uint_t nesting_ : 8; uint_t cumulative_parent_number_ : 10; uint_t is_generic_ : 1; // generic type or method parameter uint_t is_mvar_ : 1; // generic method parameter }; }; DName UnDecorator::getTemplateConstant(void) { // // template-constant ::= // '0' // '1' // '2' // char type_category = *gName++; switch (type_category) { // // template-integral-constant ::= // // case TC_integral: return getSignedDimension(); // // template-address-constant ::= // '@' // Null pointer // // case TC_address: if (*gName == TC_nullptr) { gName++; return "NULL"; } else return DName("&") + getDecoratedName(); // // template-name ::= // // case TC_name: return getDecoratedName(); // // template-floating-point-constant ::= // // case TC_fp: { DName mantissa(getSignedDimension()); DName exponent(getSignedDimension()); if (mantissa.isValid() && exponent.isValid()) { // Get string representation of mantissa char buf[100]; // Way overkill for a compiler generated fp constant if (!mantissa.getString(buf + 1, _countof(buf) - 1)) { return DN_invalid; } // Insert decimal point buf[0] = buf[1]; if (buf[0] == '-') { buf[1] = buf[2]; buf[2] = '.'; } else { buf[1] = '.'; } // String it all together return DName(buf) + 'e' + exponent; } else { return DN_truncated; } } break; case TC_vptmd: case TC_gptmd: case TC_mptmf: case TC_vptmf: case TC_gptmf: { DName ptm = '{'; switch (type_category) { case TC_mptmf: case TC_vptmf: case TC_gptmf: ptm += getDecoratedName(); ptm += ','; break; } switch (type_category) { case TC_gptmf: case TC_gptmd: ptm += getSignedDimension(); ptm += ','; // fallthrough case TC_vptmd: case TC_vptmf: ptm += getSignedDimension(); ptm += ','; // fallthrough case TC_mptmf: ptm += getSignedDimension(); } return ptm + '}'; } break; case TC_empty: return DName(); break; case TC_template_type_parameter: case TC_template_type_parameter_pack: case TC_generic_class_parameter: case TC_generic_method_parameter: { // This is a template-parameter, i.e. we have a "specialization" of X. so get the template-parameter-index and use // a "generic" name for this parameter DName dimension = getSignedDimension(); char buffer[16]; dimension.getString(buffer, _countof(buffer)); TPI_t tpi; tpi.index_ = atol(buffer); if (haveTemplateParameters() && (m_pGetParameter != nullptr)) { if (const char *pName = (*m_pGetParameter)(tpi.number_)) { return pName; } } sprintf_s(buffer, _countof(buffer), "%d", tpi.number_); DName index(buffer); switch (type_category) { case TC_template_type_parameter: case TC_template_type_parameter_pack: return "`template-type-parameter-" + index + "'"; break; case TC_generic_class_parameter: return "`generic-class-parameter-" + index + "'"; break; case TC_generic_method_parameter: return "`generic-method-parameter-" + index + "'"; break; } return DN_invalid; } break; case TC_nontype_dummy: return DN_invalid; break; case '\0': --gName; return DN_truncated; break; default: return DN_invalid; break; } } inline DName UnDecorator::composeDeclaration(const DName & symbol) { DName declaration; unsigned long chpeOffset = (unsigned long)(gName - name); unsigned int typeCode = getTypeEncoding(); int symIsUDC = symbol.isUDC(); // Handle bad typeCode's, or truncation if (TE_isbadtype(typeCode)) return DN_invalid; else if(TE_istruncated(typeCode)) return (DN_truncated + symbol); else if(TE_isCident(typeCode)) return symbol; // This is a very complex part. The type of the declaration must be // determined, and the exact composition must be dictated by this type. // Is it any type of a function ? // However, for ease of decoding, treat the 'localdtor' thunk as data, since // its decoration is a function of the variable to which it belongs and not // a usual function type of decoration. #if ( NO_COMPILER_NAMES ) if (TE_isthunk(typeCode)) return DN_invalid; if (TE_isfunction(typeCode)) #else // } elif !NO_COMPILER_NAMES { if (TE_isfunction(typeCode) && !((TE_isthunk(typeCode) && TE_islocaldtor(typeCode)) || (TE_isthunk(typeCode) && (TE_istemplatector(typeCode) || TE_istemplatedtor(typeCode))))) #endif // !NO_COMPILER_NAMES { // If it is based, then compose the 'based' prefix for the name if (TE_isbased(typeCode)) if (doMSKeywords() && doAllocationModel()) declaration = ' ' + getBasedType(); else declaration |= getBasedType(); // Just lose the 'based-type' #if ( !NO_COMPILER_NAMES ) // Check for some of the specially composed 'thunk's if (TE_isthunk(typeCode) && TE_isvcall(typeCode)) { declaration += symbol + '{' + getCallIndex(); DName thunkType = getVCallThunkType(); if (!doNameOnly()) { declaration += ',' + thunkType + "}' "; } declaration += "}'"; DName callingConvention = getCallingConvention(); if (doMSKeywords() && doAllocationLanguage() && !doNameOnly()) { declaration = ' ' + callingConvention + ' ' + declaration; // What calling convention ? } } // End of IF then else #endif // !NO_COMPILER_NAMES { DName vbptrDisp; DName vbindex; DName vtorDisp; DName adjustment; DName thisType; #if ( !NO_COMPILER_NAMES ) if (TE_isthunk(typeCode)) { if (TE_isvtoradjex(typeCode)) { vbptrDisp = getDisplacement(); vbindex = getDisplacement(); vtorDisp = getDisplacement(); } else if (TE_isvtoradj(typeCode)) { vtorDisp = getDisplacement(); } adjustment = getDisplacement(); } // End of IF else #endif // !NO_COMPILER_NAMES // Get the 'this-type' for non-static function members if (TE_ismember(typeCode) && !TE_isstatic(typeCode)) if (doThisTypes()) thisType = getThisType(); else thisType |= getThisType(); if (doMSKeywords()) { // Attach the calling convention if (doAllocationLanguage()) declaration = getCallingConvention() + declaration; // What calling convention ? else declaration |= getCallingConvention(); // Just lose the 'calling-convention' // Any model specifiers ? #if !VERS_32BIT if (doAllocationModel()) if (TE_isnear(typeCode)) declaration = UScore(TOK_nearSp) + declaration; else if(TE_isfar(typeCode)) declaration = UScore(TOK_farSp) + declaration; #endif } // End of IF else declaration |= getCallingConvention(); // Just lose the 'calling-convention' // Now put them all together if (!symbol.isEmpty()) if (!declaration.isEmpty() && !doNameOnly()) // And the symbol name declaration += ' ' + symbol; else declaration = symbol; // Compose the return type, catching the UDC case DName * pDeclarator = 0; DName returnType; if (symIsUDC) // Is the symbol a UDC operator ? { declaration += " " + getReturnType(); if (doNameOnly()) return declaration; } else { pDeclarator = gnew DName; returnType = getReturnType(pDeclarator); } // End of IF else #if ( !NO_COMPILER_NAMES ) // Add the displacements for virtual function thunks if (TE_isthunk(typeCode)) { if (TE_isvtoradjex(typeCode)) declaration += "`vtordispex{" + vbptrDisp + ',' + vbindex + ',' + vtorDisp + ','; else if (TE_isvtoradj(typeCode)) declaration += "`vtordisp{" + vtorDisp + ','; else declaration += "`adjustor{"; declaration += adjustment + "}' "; } // End of IF #endif // !NO_COMPILER_NAMES // If this is a function and we are at the top level of recursion // (i.e. not inside a template scope), save the offset as the chpe // offset. if (m_recursionLevel == 1 && m_CHPENameOffset == 0) { m_CHPENameOffset = chpeOffset; } // Add the function argument prototype declaration += '(' + getArgumentTypes() + ')'; // If this is a non-static member function, append the 'this' modifiers if (TE_ismember(typeCode) && !TE_isstatic(typeCode)) declaration += thisType; #if CC_RESTRICTION_SPEC // Add restriction modifiers if there is any if (doRestrictionSpec()) declaration += getRestrictionSpec(); else declaration |= getRestrictionSpec(); // Just lose the 'restriction specification' #endif // CC_RESTRICTION_SPEC declaration += getNoexcept(); // Add the 'throw' signature if (doThrowTypes()) declaration += getThrowTypes(); else declaration |= getThrowTypes(); // Just lose the 'throw-types' #if CC_RESTRICTION_SPEC // skip any dispatch target encoding since it's not part of original function signature declaration |= getDispatchTarget(); #endif // CC_RESTRICTION_SPEC // If it has a declarator, then insert it into the declaration, // sensitive to the return type composition if (doFunctionReturns() && pDeclarator) { *pDeclarator = declaration; declaration = returnType; } // End of IF } // End of IF else } // End of IF then else { declaration += symbol; // Catch the special handling cases #if ( !NO_COMPILER_NAMES ) if (TE_isvftable(typeCode)) return getVfTableType(declaration); else if(TE_isvbtable(typeCode)) return getVbTableType(declaration); else if(TE_isguard(typeCode)) return (declaration + '{' + getGuardNumber() + "}'"); else if(TE_isvdispmap(typeCode)) return getVdispMapType(declaration); else if(TE_isthunk(typeCode) && TE_islocaldtor(typeCode)) declaration += "`local static destructor helper'"; else if(TE_isthunk(typeCode) && TE_istemplatector(typeCode)) declaration += "`template static data member constructor helper'"; else if(TE_isthunk(typeCode) && TE_istemplatedtor(typeCode)) declaration += "`template static data member destructor helper'"; else if(TE_ismetaclass(typeCode)) // // Meta-class information has its information in its operator id // return declaration; #else // } elif NO_COMPILER_NAMES { if (TE_isvftable(typeCode) || TE_isvbtable(typeCode) || TE_isguard(typeCode) || TE_ismetaclass(typeCode)) return DN_invalid; #endif // NO_COMPILER_NAMES if (TE_isthunk(typeCode) && (TE_istemplatector(typeCode) || TE_istemplatedtor(typeCode))) { // // Insert a space before the declaration // declaration = " " + declaration; } else { // All others are decorated as data symbols declaration = getExternalDataType(declaration); } } // End of IF else // Prepend the 'virtual' and 'static' attributes for members if (TE_ismember(typeCode)) { if (doMemberTypes()) { if (TE_isstatic(typeCode)) declaration = "static " + declaration; if (TE_isvirtual(typeCode) || (TE_isthunk(typeCode) && (TE_isvtoradj(typeCode) || TE_isvtoradjex(typeCode) || TE_isadjustor(typeCode)))) declaration = "virtual " + declaration; } // End of IF // Prepend the access specifiers if (doAccessSpecifiers()) if (TE_isprivate(typeCode)) declaration = "private: " + declaration; else if(TE_isprotected(typeCode)) declaration = "protected: " + declaration; else if(TE_ispublic(typeCode)) declaration = "public: " + declaration; } // End of IF #if ( !NO_COMPILER_NAMES ) // If it is a thunk, mark it appropriately if (TE_isthunk(typeCode) && !doNameOnly()) declaration = "[thunk]:" + declaration; #endif // !NO_COMPILER_NAMES // Return the composed declaration if (TE_isexternc(typeCode)) { declaration = "extern \"C\" " + declaration; } return declaration; } // End of "UnDecorator" FUNCTION "composeDeclaration" inline int UnDecorator::getTypeEncoding(void) { unsigned int typeCode = 0u; // Strip any leading '_' which indicates that it is based if (*gName == '_') { TE_setisbased(typeCode); gName++; } // End of IF // Now handle the code proper :- if ((*gName >= 'A') && (*gName <= 'Z')) // Is it some sort of function ? { int code = *gName++ - 'A'; // Now determine the function type TE_setisfunction(typeCode); // All of them are functions ? // Determine the calling model if (code & TE_far) TE_setisfar(typeCode); else TE_setisnear(typeCode); // Is it a member function or not ? if (code < TE_external) { // Record the fact that it is a member TE_setismember(typeCode); // What access permissions does it have switch (code & TE_access) { case TE_private: TE_setisprivate(typeCode); break; case TE_protect: TE_setisprotected(typeCode); break; case TE_public: TE_setispublic(typeCode); break; default: TE_setisbadtype(typeCode); return typeCode; } // End of SWITCH // What type of a member function is it ? switch (code & TE_adjustor) { case TE_adjustor: TE_setisadjustor(typeCode); break; case TE_virtual: TE_setisvirtual(typeCode); break; case TE_static: TE_setisstatic(typeCode); break; case TE_member: break; default: TE_setisbadtype(typeCode); return typeCode; } // End of SWITCH } // End of IF } // End of IF then else if(*gName == '$') // Extended set ? Special handling { // What type of symbol is it ? bool isVtorDispThunkEx = false; switch (*(++gName)) { case SHF_localdtor: // A destructor helper for a local static ? TE_setislocaldtor(typeCode); break; case SHF_vcall: // A VCall-thunk ? TE_setisvcall(typeCode); break; case SHF_templateStaticDataMemberCtor: // A constructor helper for template static data members TE_setistemplatector(typeCode); break; case SHF_templateStaticDataMemberDtor: // A destructor helper for template static data members TE_setistemplatedtor(typeCode); break; case SHF_vdispmap: TE_setvdispmap(typeCode); break; case '$': { if (*(gName + 1) == SHF_AnyDLLImportMethod) { gName += 1; } switch (*(++gName)) { case SHF_CPPManagedILFunction: // C++ managed-IL function case SHF_CPPManagedILMain: // C++ managed-IL main case SHF_CPPManagedILDLLImportData: // C++ managed-IL DLL-import function case SHF_CPPManagedNativeDLLImportData: // C++ managed-native DLL-import function // // Skip the encoding // gName += 1; return getTypeEncoding(); case SHF_CManagedILFunction: // C (or extern "C") managed-IL function case SHF_CManagedILDLLImportData: // C (or extern "C") managed-IL DLL-import function case SHF_CManagedNativeDLLImportData: // C (or extern "C") managed-native DLL-import function { // // Skip the encoding // gName += 1; // // The next character should be the number of characters // in the byte-count // if ((*gName >= '0') && (*gName <= '9')) { // // Skip the character count and the byte-count // itself // gName += ((*gName - '0') + 1); typeCode = getTypeEncoding(); TE_setisisexternc(typeCode); return typeCode; } else { TE_setisbadtype(typeCode); } } break; case MGD_AppDomain: { gName += 1; // this is __declspec(appdomain), but we won't say it return getTypeEncoding(); } case SHF_Hybrid: { m_CHPENameOffset = 0; // clear the chpe name offset because this name is already chpe gName += 1; return getTypeEncoding(); } case 0: TE_setistruncated ( typeCode ); return typeCode; default: TE_setisbadtype(typeCode); return typeCode; } } break; case 0: TE_setistruncated(typeCode); --gName; // back up, we advance back to the NUL below break; case SHF_VtorDispThunkEx: isVtorDispThunkEx = true; ++gName; if (*gName < '0' || *gName > '5') // case labels below { if (*gName) TE_setistruncated(typeCode); else TE_setisbadtype(typeCode); return typeCode; } //fallthrough case '0': case '1': case '2': case '3': case '4': case '5': // Construction displacement adjustor thunks { int code = *gName - '0'; // Set up the principal type information TE_setisfunction(typeCode); TE_setismember(typeCode); if (isVtorDispThunkEx) TE_setisvtoradjex(typeCode); else TE_setisvtoradj(typeCode); // Is it 'near' or 'far' ? if (code & TE_far) TE_setisfar(typeCode); else TE_setisnear(typeCode); // What type of access protection ? switch (code & TE_access_vadj) { case TE_private_vadj: TE_setisprivate(typeCode); break; case TE_protect_vadj: TE_setisprotected(typeCode); break; case TE_public_vadj: TE_setispublic(typeCode); break; default: TE_setisbadtype(typeCode); return typeCode; } // End of SWITCH } // End of CASE '0,1,2,3,4,5' break; default: TE_setisbadtype(typeCode); return typeCode; } // End of SWITCH // Advance past the code character gName++; } // End of else if then else if((*gName >= TE_static_d) && (*gName <= TE_metatype)) // Non function decorations ? { int code = *gName++; TE_setisdata(typeCode); // What type of symbol is it ? switch (code) { case (TE_static_d | TE_private_d): TE_setisstatic(typeCode); TE_setisprivate(typeCode); break; case (TE_static_d | TE_protect_d): TE_setisstatic(typeCode); TE_setisprotected(typeCode); break; case (TE_static_d | TE_public_d): TE_setisstatic(typeCode); TE_setispublic(typeCode); break; case TE_global: TE_setisglobal(typeCode); break; case TE_guard: TE_setisguard(typeCode); break; case TE_local: TE_setislocal(typeCode); break; case TE_vftable: TE_setisvftable(typeCode); break; case TE_vbtable: TE_setisvbtable(typeCode); break; case TE_metatype: TE_setismetaclass(typeCode); break; default: TE_setisbadtype(typeCode); return typeCode; } // End of SWITCH } // End of else if then else if(*gName == '9') { gName++; TE_setisCident(typeCode); } else if(*gName) TE_setisbadtype(typeCode); else TE_setistruncated(typeCode); // Return the composed type code return typeCode; } // End of "UnDecorator" FUNCTION "getTypeEncoding" DName UnDecorator::getBasedType(void) { DName basedDecl(UScore(TOK_basedLp)); // What type of 'based' is it ? if (*gName) { switch (*gName++) { #if !VERS_32BIT case BT_segname: basedDecl += UScore(TOK_segnameLpQ) + getSegmentName() + "\")"; break; case BT_segment: basedDecl += DName("NYI:") + UScore(TOK_segment); break; #endif case BT_void: basedDecl += "void"; break; #if !VERS_32BIT case BT_self: basedDecl += UScore(TOK_self); break; case BT_nearptr: basedDecl += DName("NYI:") + UScore(TOK_nearP); break; case BT_farptr: basedDecl += DName("NYI:") + UScore(TOK_farP); break; case BT_hugeptr: basedDecl += DName("NYI:") + UScore(TOK_hugeP); break; case BT_segaddr: basedDecl += "NYI:"; break; #else case BT_nearptr: basedDecl += getScopedName(); break; #endif case BT_basedptr: // // Note: based pointer on based pointer is reserved // return DN_invalid; } // End of SWITCH } // End of IF else else basedDecl += DN_truncated; // Close the based syntax basedDecl += ") "; // Return completed based declaration return basedDecl; } // End of "UnDecorator" FUNCTION "getBasedType" DName UnDecorator::getScopedName(void) { DName scopeName; // Get the beginning of the name scopeName = getZName(true); // Now the scope (if any) if ((scopeName.status() == DN_valid) && *gName && (*gName != '@')) scopeName = getScope() + "::" + scopeName; // Skip the trailing '@' if (*gName == '@') gName++; else if(*gName) scopeName = DN_invalid; else if(scopeName.isEmpty()) scopeName = DN_truncated; else scopeName = DName(DN_truncated) + "::" + scopeName; // And return the complete name return scopeName; } // End of "UnDecorator" FUNCTION "getECSUName" inline DName UnDecorator::getECSUName(void) { return getScopedName(); } inline DName UnDecorator::getEnumType(void) { DName ecsuName; if (*gName) { // What type of an 'enum' is it ? switch (*gName) { case ET_schar: case ET_uchar: ecsuName = "char "; break; case ET_sshort: case ET_ushort: ecsuName = "short "; break; case ET_sint: break; case ET_uint: ecsuName = "int "; break; case ET_slong: case ET_ulong: ecsuName = "long "; break; default: return DN_invalid; } // End of SWITCH // Add the 'unsigned'ness if appropriate switch (*gName++) { case ET_uchar: case ET_ushort: case ET_uint: case ET_ulong: ecsuName = "unsigned " + ecsuName; break; } // End of SWITCH // Now return the composed name return ecsuName; } // End of IF then else return DN_truncated; } // End of "UnDecorator" FUNCTION "getEnumType" DName UnDecorator::getCallingConvention(void) { if (*gName) { unsigned int callCode = ((unsigned int)*gName++) - 'A'; // What is the primary calling convention DASSERT(CC_cdecl == 0); if (/*( callCode >= CC_cdecl ) &&*/(callCode <= CC_last)) { DName callType = DN_invalid; // Now, what type of 'calling-convention' is it, 'interrupt' is special ? if (doMSKeywords()) #if !VERS_32BIT if (callCode == CC_interrupt) callType = UScore(TOK_interrupt); else #endif { switch (callCode & ~CC_saveregs) { case CC_cdecl: callType = UScore(TOK_cdecl); break; case CC_pascal: callType = UScore(TOK_pascal); break; case CC_thiscall: callType = UScore(TOK_thiscall); break; case CC_stdcall: callType = UScore(TOK_stdcall); break; case CC_fastcall: callType = UScore(TOK_fastcall); break; case CC_vectorcall: callType = UScore(TOK_vectorcall); break; case CC_cocall: callType = UScore(TOK_cocall); break; case CC_eabi: callType = UScore(TOK_eabi); break; case CC_swift_1: callType = UScore(TOK_swift_1); break; case CC_swift_2: callType = UScore(TOK_swift_2); break; } // End of SWITCH // Has it also got 'saveregs' marked ? #if !VERS_32BIT if (callCode & CC_saveregs) callType += ' ' + UScore(TOK_saveregs); #endif } // End of IF else // And return return callType; } // End of IF then else return DN_invalid; } // End of IF then else return DN_truncated; } // End of "UnDecorator" FUNCTION "getCallingConvention" DName UnDecorator::getReturnType(DName * pDeclarator) { if (*gName == '@') // Return type for constructors and destructors ? { gName++; return DName(pDeclarator); } // End of IF then else return getDataType(pDeclarator); } // End of "UnDecorator" FUNCTION "getReturnType" DName UnDecorator::getDataType(DName * pDeclarator) { DName superType(pDeclarator); // What type is it ? switch (*gName) { case 0: return (DN_truncated + superType); case BDT_void: gName++; if (superType.isEmpty()) return "void"; else return "void " + superType; case '?': { gName++; // Skip the '?' const char *pStr = ""; superType = getDataIndirectType(superType, pStr, DName(), 0); return getPrimaryDataType(superType); return superType; } // End of CASE '?' default: return getPrimaryDataType(superType); } // End of SWITCH } // End of "UnDecorator" FUNCTION "getDataType" DName UnDecorator::getPrimaryDataType(const DName & superType) { DName cvType; switch (*gName) { case 0: return (DN_truncated + superType); case PDT_volatileReference: cvType = "volatile"; if (!superType.isEmpty()) cvType += ' '; // No break case PDT_reference: { DName superName(superType); gName++; const char* pStr = "&"; return getReferenceType(cvType, superName.setPtrRef(), pStr); } // End of CASE 'PDT_reference' case PDT_extend: { // // Extended Primary Data Type (items overlooked in original design): // prefixed by '$$'. // if (gName[1] != PDT_extend) if (gName[1] == '\0') return DN_truncated + superType; else return DN_invalid; gName += 2; switch (*gName) { case PDT_ex_function: gName++; return getFunctionIndirectType(superType); case PDT_ex_other: gName++; return getPtrRefDataType(superType, /* isPtr = */ TRUE); case PDT_ex_qualified: { gName++; const char *pStr = ""; return getBasicDataType(getDataIndirectType(superType, pStr, DName(), 0)); } break; case PDT_ex_vol_rvalue_ref: cvType = "volatile"; if (!superType.isEmpty()) { cvType += ' '; } // No break case PDT_ex_rvalue_ref: { DName superName(superType); gName++; const char* pStr = "&&"; return getReferenceType(cvType, superName.setPtrRef(), pStr); } case PDT_ex_nullptr: gName++; return DN_invalid; break; case PDT_ex_nullptr_t: gName++; if (!superType.isEmpty()) { return "std::nullptr_t " + superType; } else { return "std::nullptr_t"; } break; case PDT_aliasTemplate: gName++; return getScopedName(); case 0: return (DN_truncated + superType); default: return DN_invalid; } } default: return getBasicDataType(superType); } // End of SWITCH } // End of "UnDecorator" FUNCTION "getPrimaryDataType" DName UnDecorator::getArgumentTypes(void) { switch (*gName) { case AT_ellipsis: return (gName++, doEllipsis() ? "..." : UNDNAME_ELLIPSIS_ALTERNATE); case AT_void: return (gName++, "void"); default: { DName arguments(getArgumentList()); // Now, is it a varargs function or not ? if (arguments.status() == DN_valid) switch (*gName) { case 0: return arguments; case AT_ellipsis: return (gName++, arguments + (doEllipsis() ? ",..." : "," UNDNAME_ELLIPSIS_ALTERNATE)); case AT_endoflist: return (gName++, arguments); default: return DN_invalid; } // End of SWITCH else return arguments; } // End of DEFAULT } // End of SWITCH } // End of "UnDecorator" FUNCTION "getArgumentTypes" DName UnDecorator::getArgumentList(void) { int first = TRUE; DName aList; while ((aList.status() == DN_valid) && (*gName != AT_endoflist) && (*gName != AT_ellipsis)) { // Insert the argument list separator if not the first argument if (first) first = FALSE; else aList += ','; // Get the individual argument type if (*gName) { int argIndex = *gName - '0'; // Handle 'argument-replicators', otherwise a new argument type if ((argIndex >= 0) && (argIndex <= 9)) { gName++; // Skip past the replicator // Append to the argument list aList += (*pArgList)[argIndex]; } // End of IF then else { pcchar_t oldGName = gName; // Extract the 'argument' type DName arg(getPrimaryDataType(DName())); // Add it to the current list of 'argument's, if it is bigger than a one byte encoding if (((gName - oldGName) > 1) && !pArgList->isFull()) *pArgList += arg; // Append to the argument list aList += arg; #if 1 if (gName == oldGName) // prevent endless loop on invalid input aList = DN_invalid; #endif } // End of IF else } // End of IF then else { aList += DN_truncated; break; } // End of IF else } // End of WHILE // Return the completed argument list return aList; } // End of "UnDecorator" FUNCTION "getArgumentList" DName UnDecorator::getThrowTypes(void) { // Handle the 'throw types'. This should never have been part of the name encoding at // all -- dynamic exception specifications were never part of a function type -- but someone // long ago decided that this was a good idea and we're stuck with it. // // For C++17 noexcept function encodings, for those functions where noexcept *is* encoded // on the type, we will not emit the ellipsis. In this case we will undecorate nothing here. // Top-level noexcept functions still have the ellipsis encoded, however, to maintain // ABI compatibility with C++14 and earlier code. if (*gName == AT_ellipsis) return (gName++, DName()); else return DName(); } // End of "UnDecorator" FUNCTION "getThrowTypes" DName UnDecorator::getNoexcept() { if (*gName && *gName == '_' && *(gName + 1) && *(gName + 1) == FT_noexcept) { gName += 2; return " noexcept"; } return DName(); } #if CC_RESTRICTION_SPEC DName UnDecorator::getRestrictionSpec(void) { if (*gName && *gName == '_' && *(gName+1) && *(gName+1) <= FT_restrict_cpuamp) { // Skip the escape char '_' first gName++; unsigned int rstCode = ((unsigned int)*gName++) - 'A'; if (rstCode <= RST_MASK) { DName restrictionMods; if (doMSKeywords()) { restrictionMods += " "; restrictionMods += UScore(TOK_restrictSpecLp); while (rstCode != 0) { unsigned int nextRstCode = (~rstCode + 1) & rstCode; switch (nextRstCode) { case RST_cpu: restrictionMods += "cpu"; break; #if CC_DP_CXX case RST_amp: restrictionMods += "amp"; break; #endif // CC_DP_CXX default: return DN_invalid; } rstCode &= ~nextRstCode; if (rstCode != 0) { restrictionMods += ", "; } } restrictionMods += ')'; } // End of IF else return restrictionMods; } // End of IF then else return DN_invalid; } // End of IF then else return DName(); } // End of "UnDecorator" FUNCTION "getRestrictionSpec" DName UnDecorator::getDispatchTarget(void) { if (*gName && *gName == '_' && *(gName + 1) && *(gName + 1) == '_') { // Skip the escape prefix '__' first gName++; gName++; unsigned int rstCode = ((unsigned int)*gName++) - 'A'; if (rstCode > RST_MASK) { // not a valid dispatch target return DN_invalid; } } // dispatch target does not need to be undecorated since it's not part of the original function // signature. Just need to skip though it. return DName(); } #endif // CC_RESTRICTION_SPEC DName UnDecorator::getBasicDataType(const DName & superType) { if (*gName) { unsigned char bdtCode = *gName++; unsigned char extended_bdtCode = 0x0; int pCvCode = -1; DName basicDataType; // Extract the principal type information itself, and validate the codes switch (bdtCode) { case BDT_schar: case BDT_char: case (BDT_char | BDT_unsigned): basicDataType = "char"; break; case BDT_short: case (BDT_short | BDT_unsigned): basicDataType = "short"; break; case BDT_int: case (BDT_int | BDT_unsigned): basicDataType = "int"; break; case BDT_long: case (BDT_long | BDT_unsigned): basicDataType = "long"; break; #if !VERS_32BIT case BDT_segment: basicDataType = UScore(TOK_segment); break; #endif case BDT_float: basicDataType = "float"; break; case BDT_longdouble: basicDataType = "long "; // No break case BDT_double: basicDataType += "double"; break; case BDT_pointer: case (BDT_pointer | BDT_const): case (BDT_pointer | BDT_volatile): case (BDT_pointer | BDT_const | BDT_volatile): pCvCode = (bdtCode & (BDT_const | BDT_volatile)); break; case BDT_extend: switch (extended_bdtCode = *gName++) { case BDT_array: pCvCode = -2; break; case BDT_bool: basicDataType = "bool"; break; case BDT_int8: case (BDT_int8 | BDT_unsigned): basicDataType = "__int8"; break; case BDT_int16: case (BDT_int16 | BDT_unsigned): basicDataType = "__int16"; break; case BDT_int32: case (BDT_int32 | BDT_unsigned): basicDataType = "__int32"; break; case BDT_int64: case (BDT_int64 | BDT_unsigned): basicDataType = "__int64"; break; case BDT_int128: case (BDT_int128 | BDT_unsigned): basicDataType = "__int128"; break; case BDT_unknown: basicDataType = ""; break; case BDT_char16_t: basicDataType = "char16_t"; break; case BDT_char32_t: basicDataType = "char32_t"; break; case BDT_wchar_t: // So that we get diagnostics like we want them basicDataType = "wchar_t"; break; #if CC_COR case BDT_coclass: case BDT_cointerface: { gName--; // Backup, since 'ecsu-data-type' does it's own decoding basicDataType = getECSUDataType(); if (basicDataType.isEmpty()) { return basicDataType; } } break; #endif // CC_COR case '$': return "__w64 " + getBasicDataType(superType); case '\0': gName--; // End of string, better back-up basicDataType = DN_truncated; break; default: basicDataType = "UNKNOWN"; break; } break; case BDT_void: basicDataType = "void"; break; default: gName--; // Backup, since 'ecsu-data-type' does it's own decoding basicDataType = getECSUDataType(); if (basicDataType.isEmpty()) return basicDataType; break; } // End of SWITCH // What type of basic data type composition is involved ? if (pCvCode == -1) // Simple ? { // Determine the 'signed/unsigned'ness switch (bdtCode) { case (BDT_char | BDT_unsigned): case (BDT_short | BDT_unsigned): case (BDT_int | BDT_unsigned): case (BDT_long | BDT_unsigned): basicDataType = "unsigned " + basicDataType; break; case BDT_schar: basicDataType = "signed " + basicDataType; break; case BDT_extend: switch (extended_bdtCode) { case (BDT_int8 | BDT_unsigned): case (BDT_int16 | BDT_unsigned): case (BDT_int32 | BDT_unsigned): case (BDT_int64 | BDT_unsigned): case (BDT_int128 | BDT_unsigned): basicDataType = "unsigned " + basicDataType; break; } // End of SWITCH break; } // End of SWITCH // Add the indirection type to the type if (!superType.isEmpty()) basicDataType += ' ' + superType; // And return the completed type return basicDataType; } // End of IF then else { DName cvType; DName superName(superType); if (pCvCode == -2) { superName.setIsArray(); DName arType = getPointerTypeArray(cvType, superName); // if we didn't get back an array, append. // A multidimensional array sticks the braces in before the // other dimensions at sets isArray on it's return type. if (!arType.isArray()) { arType += "[]"; } return arType; } // Is it 'const/volatile' qualified ? if (superType.isEmpty()) { // // const/volatile are redundantly encoded, except at the start // of a "type only" context. In such a context, the super-type // is empty. // if (pCvCode & BDT_const) { cvType = "const"; if (pCvCode & BDT_volatile) cvType += " volatile"; } // End of IF then else if(pCvCode & BDT_volatile) cvType = "volatile"; } // End of IF then // Construct the appropriate pointer type declaration return getPointerType(cvType, superName); } // End of IF else } // End of IF then else return (DN_truncated + superType); } // End of "UnDecorator" FUNCTION "getBasicDataType" DName UnDecorator::getECSUDataType(void) { // Extract the principal type information itself, and validate the codes int fPrefix = doEcsu() && !doNameOnly(); DName Prefix; switch (*gName++) { case 0: gName--; // Backup to permit later error recovery to work safely return "`unknown ecsu'" + DN_truncated; case BDT_union: Prefix = "union "; break; case BDT_struct: Prefix = "struct "; break; case BDT_class: Prefix = "class "; break; #if CC_COR case BDT_coclass: Prefix = "coclass "; break; case BDT_cointerface: Prefix = "cointerface "; break; #endif // CC_COR case BDT_enum: fPrefix = doEcsu(); Prefix = "enum " + getEnumType(); break; // default: // return DN_invalid; } // End of SWITCH DName ecsuDataType; if (fPrefix) ecsuDataType = Prefix; // Get the 'class/struct/union' name ecsuDataType += getECSUName(); // And return the formed 'ecsu-data-type' return ecsuDataType; } // End of "UnDecorator" FUNCTION "getECSUDataType" // // Undecorator::getFunctionIndirectType // // Note: this function gets both the function-indirect-type and the function-type. // DName UnDecorator::getFunctionIndirectType(const DName & superType) { if (!*gName) return DN_truncated + superType; if (!IT_isfunction(*gName)) return DN_invalid; int fitCode = *gName++ - '6'; if (fitCode == ('_' - '6')) { if (*gName) { fitCode = *gName++ - 'A' + FIT_based; if ((fitCode < FIT_based) || (fitCode > (FIT_based | FIT_far | FIT_member))) fitCode = -1; } // End of IF then else return (DN_truncated + superType); } // End of IF then else if((fitCode < FIT_near) || (fitCode > (FIT_far | FIT_member))) fitCode = -1; // Return if invalid name if (fitCode == -1) return DN_invalid; // Otherwise, what are the function indirect attributes DName thisType; DName fitType = superType; // Is it a pointer to member function ? if (fitCode & FIT_member) { if (*gName != '@') { fitType = "::" + fitType; if (*gName) fitType = ' ' + getScope() + fitType; else fitType = DN_truncated + fitType; } else { // Pseudo this pointer gName++; } if (*gName) if (*gName == '@') gName++; else return DN_invalid; else return (DN_truncated + fitType); if (doThisTypes()) thisType = getThisType(); else thisType |= getThisType(); } // End of IF // Is it a based allocated function ? if (fitCode & FIT_based) if (doMSKeywords()) fitType = ' ' + getBasedType() + fitType; else fitType |= getBasedType(); // Just lose the 'based-type' // Get the 'calling-convention' if (doMSKeywords()) { fitType = getCallingConvention() + fitType; // Is it a near or far function pointer #if !VERS_32BIT fitType = UScore(((fitCode & FIT_far) ? TOK_farSp : TOK_nearSp)) + fitType; #endif } // End of IF then else fitType |= getCallingConvention(); // Just lose the 'calling-convention' // Parenthesise the indirection component, and work on the rest if (!superType.isEmpty()) { fitType = '(' + fitType + ')'; } // Get the rest of the 'function-type' pieces DName * pDeclarator = gnew DName; DName returnType(getReturnType(pDeclarator)); fitType += '(' + getArgumentTypes() + ')'; if (doThisTypes() && (fitCode & FIT_member)) fitType += thisType; // See the note in outdname.c EncodeFunctionTypes for the structure of optional // flags that can appear after the argument list in a function type. #if CC_RESTRICTION_SPEC if (doRestrictionSpec()) fitType += getRestrictionSpec(); else fitType |= getRestrictionSpec(); // Just lose the 'restriction specification' #endif // CC_RESTRICTION_SPEC // If the name encoded noexcept on a function pointer, emit it unconditionally. Only code // compiled with -std:c++17 or later will encode these. fitType += getNoexcept(); if (doThrowTypes()) fitType += getThrowTypes(); else fitType |= getThrowTypes(); // Just lose the 'throw-types' // Now insert the indirected declarator, catch the allocation failure here if (pDeclarator) *pDeclarator = fitType; else return DN_error; // And return the composed function type (now in 'returnType' ) return returnType; } DName UnDecorator::getPtrRefType(const DName & cvType, const DName & superType, const char* ptrChar) { DASSERT((ptrChar != NULL) && ((*ptrChar == '*') || (*ptrChar == '&') || (*ptrChar == '^') || (*ptrChar == '%') || (*ptrChar == '\0'))); // Doubles up as 'pointer-type' and 'reference-type' if (*gName) if (IT_isfunction(*gName)) // Is it a function or data indirection ? { DName fitType = ptrChar; if (!cvType.isEmpty() && (superType.isEmpty() || !superType.isPtrRef())) fitType += cvType; if (!superType.isEmpty()) fitType += superType; return getFunctionIndirectType(fitType); } // End of IF then else { // Otherwise, it is either a pointer or a reference to some data type DName innerType(getDataIndirectType(superType, ptrChar, cvType)); return getPtrRefDataType(innerType, *ptrChar == '*'); } // End of IF else else { DName trunk(DN_truncated); trunk += ptrChar; if (!cvType.isEmpty()) trunk += cvType; if (!superType.isEmpty()) { if (!cvType.isEmpty()) trunk += ' '; trunk += superType; } // End of IF return trunk; } // End of IF else } // End of "UnDecorator" FUNCTION "getPtrRefType" DName UnDecorator::getExtendedDataIndirectType(const char*& prType, bool& fIsPinPtr, int thisFlag) { DASSERT((prType != NULL) && ((*prType == '*') || (*prType == '&') || (*prType == '^') || (*prType == '%') || (*prType == '\0'))); DName szComPlusIndirSpecifier; DASSERT(*gName == '$'); gName++; // swallow up the dollar switch (*gName) { case DIT_GCPointer: // Don't print ^ if we're undecorating the 'this' pointer if (!thisFlag) { if (*prType == '&') prType = "%"; if (*prType == '*') prType = "^"; } gName++; break; case DIT_PinPointer: // DASSERT(!thisFlag); // validate, don't assert if (thisFlag) return DN_invalid; fIsPinPtr = true; szComPlusIndirSpecifier = '>'; gName++; break; case DIT_InteriorPointer: // this pointer of value class is interior_ptr prType = "%"; gName++; break; default: if (!gName[0] || !gName[1]) return DN_truncated; // DASSERT(!thisFlag); // validate, don't assert if (thisFlag) return DN_invalid; unsigned int nRank = ((gName[0] - '0') << 4) + (gName[1] - '0'); gName += 2; if (nRank > 1) { szComPlusIndirSpecifier = ','; szComPlusIndirSpecifier = szComPlusIndirSpecifier + DName((unsigned __int64)nRank); } szComPlusIndirSpecifier = szComPlusIndirSpecifier + '>'; if (*gName == '$') { // Skip the "incomplete" com array marker. There is no // way to express this construct in the old syntax. In // the new syntax, this tells us the difference between: // // array^ // and: array gName++; } else { szComPlusIndirSpecifier = szComPlusIndirSpecifier + '^'; } if (*gName) gName++; else szComPlusIndirSpecifier += DN_truncated; szComPlusIndirSpecifier.setIsComArray(); return szComPlusIndirSpecifier; } return DName(); } DName UnDecorator::getDataIndirectType(const DName & superType, const char* prType, const DName & cvType, int thisFlag) { DASSERT((prType != NULL) && ((*prType == '*') || (*prType == '&') || (*prType == '^') || (*prType == '%') || (*prType == '\0'))); DName szComPlusIndirSpecifier; bool bIsPinPtr = false; if (*gName) { if (gName[0] == '$') { DName result = getExtendedDataIndirectType(prType, bIsPinPtr, thisFlag); if (!result.isEmpty()) { return result; } } unsigned int ditCode = (*gName - ((*gName >= 'A') ? (unsigned int)'A' : (unsigned int)('0' - 26))); DName msExtension; DName msExtensionPre; int fContinue = TRUE; bool isLrefQualifier = false; bool isRrefQualifier = false; do { switch (ditCode) { case DIT_ptr64: if (doMSKeywords() && doPtr64()) { if (!msExtension.isEmpty()) msExtension = msExtension + ' ' + UScore(TOK_ptr64); else msExtension = UScore(TOK_ptr64); } break; case DIT_unaligned: if (doMSKeywords()) { if (!msExtensionPre.isEmpty()) msExtensionPre = msExtensionPre + ' ' + UScore(TOK_unaligned); else msExtensionPre = UScore(TOK_unaligned); } break; case DIT_restrict: if (doMSKeywords()) { if (!msExtension.isEmpty()) msExtension = msExtension + ' ' + UScore(TOK_restrict); else msExtension = UScore(TOK_restrict); } break; case DIT_lref: if (!thisFlag) { return DN_invalid; } isLrefQualifier = true; break; case DIT_rref: if (!thisFlag) { return DN_invalid; } isRrefQualifier = true; break; default: fContinue = FALSE; break; } if (fContinue) { gName++; if (gName[0] == '$') { DName result = getExtendedDataIndirectType(prType, bIsPinPtr, thisFlag); if (!result.isEmpty()) { return result; } } ditCode = (*gName - ((*gName >= 'A') ? (unsigned int)'A' : (unsigned int)('0' - 26))); } } while (fContinue); if (*gName) gName++; // Skip to next character in name // Is it a valid 'data-indirection-type' ? DASSERT(DIT_near == 0); if ((ditCode <= (DIT_const | DIT_volatile | DIT_modelmask | DIT_member))) { DName ditType(prType); ditType = szComPlusIndirSpecifier + ditType; if (!msExtension.isEmpty()) ditType = ditType + ' ' + msExtension; if (!msExtensionPre.isEmpty()) ditType = msExtensionPre + ' ' + ditType; // If it is a member, then these attributes immediately precede the indirection token if (ditCode & DIT_member) { // If it is really 'this-type', then it cannot be any form of pointer to member if (thisFlag) return DN_invalid; // Otherwise, extract the scope for the PM if (*prType != '\0') { ditType = "::" + ditType; if (*gName) ditType = getScope() + ditType; else ditType = DN_truncated + ditType; } else if(*gName) { // // The scope is ignored for special uses of data-indirect-type, such // as storage-convention. I think it's a bug that we ever mark things // with Member storage convention, as that is already covered in the // scope of the name. However, we don't want to change the dname scheme, // so we're stuck with it. // ditType |= getScope(); } // Now skip the scope terminator if (!*gName) ditType += DN_truncated; else if(*gName++ != '@') return DN_invalid; } // End of IF // Add the 'model' attributes (prefixed) as appropriate if (doMSKeywords()) { switch (ditCode & DIT_modelmask) { #if !VERS_32BIT case DIT_near: if (do32BitNear()) ditType = UScore(TOK_near) + ditType; break; case DIT_far: ditType = UScore(TOK_far) + ditType; break; case DIT_huge: ditType = UScore(TOK_huge) + ditType; break; #endif case DIT_based: // The 'this-type' can never be 'based' if (thisFlag) return DN_invalid; ditType = getBasedType() + ditType; break; } // End of SWITCH } // End of IF else if((ditCode & DIT_modelmask) == DIT_based) ditType |= getBasedType(); // Just lose the 'based-type' // Handle the 'const' and 'volatile' attributes if (ditCode & DIT_volatile) ditType = "volatile " + ditType; if (ditCode & DIT_const) ditType = "const " + ditType; if (isLrefQualifier) ditType = ditType + "& "; if (isRrefQualifier) ditType = ditType + "&& "; // Append the supertype, if not 'this-type' if (!thisFlag) if (!superType.isEmpty()) { // Is the super context included 'cv' information, ensure that it is added appropriately if (superType.isPtrRef() || cvType.isEmpty()) if (superType.isArray()) ditType = superType; // array type, skip space else ditType += ' ' + superType; else ditType += ' ' + cvType + ' ' + superType; } // End of IF then else if(!cvType.isEmpty()) ditType += ' ' + cvType; // Make sure qualifiers aren't re-applied ditType.setPtrRef(); if (bIsPinPtr) { ditType.setIsPinPtr(); } // Finally, return the composed 'data-indirection-type' (with embedded sub-type) return ditType; } // End of IF then else return DN_invalid; } // End of IF then else if(!thisFlag && !superType.isEmpty()) { // Is the super context included 'cv' information, ensure that it is added appropriately if (superType.isPtrRef() || cvType.isEmpty()) return (DN_truncated + superType); else return (DN_truncated + cvType + ' ' + superType); } // End of else if then else if(!thisFlag && !cvType.isEmpty()) return (DN_truncated + cvType); else return DN_truncated; } // End of "UnDecorator" FUNCTION "getDataIndirectType" DName UnDecorator::getPtrRefDataType(const DName& superType, int isPtr) { // Doubles up as 'pointer-data-type' and 'reference-data-type' if (*gName != '\0') { // Is this a 'pointer-data-type'? if (isPtr) { if (*gName == PoDT_void) { gName++; // Skip this character if (superType.isEmpty()) { return "void"; } return "void " + superType; } // If this is the encoding for a boxed type then skip over it and continue with the underlying type if ((gName[0] == BDT_extend) && (gName[1] == BDT_extend) && (gName[2] == BDT_boxed)) { gName += 3; } } // Otherwise it may be std::nullptr_t which has special decoration if ((gName[0] == PDT_extend) && (gName[1] == PDT_extend) && (gName[2] == PDT_ex_nullptr_t)) { gName += 3; if (superType.isEmpty()) { return "std::nullptr_t"; } else { return "std::nullptr_t " + superType; } } // Otherwise it may be a 'reference-data-type' if (*gName == RDT_array) // An array ? { gName++; return getArrayType(superType); } // Otherwise, it is a 'basic-data-type' DName bdt = getBasicDataType(superType); if (superType.isComArray()) { bdt = "cli::array<" + bdt; } else if (superType.isPinPtr()) { bdt = "cli::pin_ptr<" + bdt; } return bdt; } else { return(DN_truncated + superType); } } inline DName UnDecorator::getArrayType(const DName & superType) { if (*gName) { int noDimensions = getNumberOfDimensions(); if (noDimensions < 0) noDimensions = 0; if (!noDimensions) return getBasicDataType(DName('[') + DN_truncated + ']'); else { DName arrayType; if (superType.isArray()) { arrayType += "[]"; } while (arrayType.isValid() && noDimensions-- && *gName) arrayType += '[' + getDimension() + ']'; // If it is indirect, then parenthesise the 'super-type' if (!superType.isEmpty()) if (superType.isArray()) arrayType = superType + arrayType; else arrayType = '(' + superType + ')' + arrayType; // Return the finished array dimension information DName newType = getPrimaryDataType(arrayType); newType.setIsArray(); return newType; } // End of IF else } // End of IF else if(!superType.isEmpty()) return getBasicDataType('(' + superType + ")[" + DN_truncated + ']'); else return getBasicDataType(DName('[') + DN_truncated + ']'); } // End of "UnDecorator" FUNCTION "getArrayType" inline DName UnDecorator::getLexicalFrame(void) { return '`' + getDimension() + '\''; } inline DName UnDecorator::getStorageConvention(void) { return getDataIndirectType(); } inline DName UnDecorator::getDataIndirectType() { const char *pStr = ""; return getDataIndirectType(DName(), pStr, DName()); } inline DName UnDecorator::getThisType() { const char *pStr = ""; return getDataIndirectType(DName(), pStr, DName(), TRUE); } inline DName UnDecorator::getPointerType(const DName& cv, const DName& superType) { const char* pStr = "*"; return getPtrRefType(cv, superType, pStr); } inline DName UnDecorator::getPointerTypeArray(const DName& cv, const DName& superType) { const char* pStr = ""; return getPtrRefType(cv, superType, pStr); } inline DName UnDecorator::getReferenceType(const DName& cv, const DName& superType, const char* ptrChar) { return getPtrRefType(cv, superType, ptrChar); } inline DName UnDecorator::getSegmentName(void) { return getZName(true); } #if ( !NO_COMPILER_NAMES ) inline DName UnDecorator::getDisplacement(void) { return getDimension(true); } inline DName UnDecorator::getCallIndex(void) { return getDimension(); } inline DName UnDecorator::getGuardNumber(void) { return getDimension(); } inline DName UnDecorator::getVbTableType(const DName & superType) { return getVfTableType(superType); } inline DName UnDecorator::getVCallThunkType(void) { #if VERS_32BIT switch (*gName) { case VMT_nTnCnV: ++gName; return DName("{flat}"); case 0: return DN_truncated; default: return DN_invalid; } #else DName vcallType = '{'; // Get the 'this' model, and validate all values switch (*gName) { case VMT_nTnCnV: case VMT_nTfCnV: case VMT_nTnCfV: case VMT_nTfCfV: case VMT_nTnCbV: case VMT_nTfCbV: vcallType += UScore(TOK_nearSp); break; case VMT_fTnCnV: case VMT_fTfCnV: case VMT_fTnCfV: case VMT_fTfCfV: case VMT_fTnCbV: case VMT_fTfCbV: vcallType += UScore(TOK_farSp); break; case 0: return DN_truncated; default: return DN_invalid; } // End of SWITCH // Always append 'this' vcallType += "this, "; // Get the 'call' model switch (*gName) { case VMT_nTnCnV: case VMT_fTnCnV: case VMT_nTnCfV: case VMT_fTnCfV: case VMT_nTnCbV: case VMT_fTnCbV: vcallType += UScore(TOK_nearSp); break; case VMT_nTfCnV: case VMT_fTfCnV: case VMT_nTfCfV: case VMT_fTfCfV: case VMT_nTfCbV: case VMT_fTfCbV: vcallType += UScore(TOK_farSp); break; } // End of SWITCH // Always append 'call' vcallType += "call, "; // Get the 'vfptr' model switch (*gName++) // Last time, so advance the pointer { case VMT_nTnCnV: case VMT_nTfCnV: case VMT_fTnCnV: case VMT_fTfCnV: vcallType += UScore(TOK_nearSp); break; case VMT_nTnCfV: case VMT_nTfCfV: case VMT_fTnCfV: case VMT_fTfCfV: vcallType += UScore(TOK_farSp); break; case VMT_nTfCbV: case VMT_fTnCbV: case VMT_fTfCbV: case VMT_nTnCbV: vcallType += getBasedType(); break; } // End of SWITCH // Always append 'vfptr' vcallType += "vfptr}"; // And return the resultant 'vcall-model-type' return vcallType; #endif } // End of "UnDecorator" FUNCTION "getVCallThunk" inline DName UnDecorator::getVfTableType(const DName & superType) { DName vxTableName = superType; if (vxTableName.isValid() && *gName) { vxTableName = getStorageConvention() + ' ' + vxTableName; if (vxTableName.isValid()) { if (*gName != '@') { vxTableName += "{for "; while (vxTableName.isValid() && *gName && (*gName != '@')) { vxTableName += '`' + getScope() + '\''; // Skip the scope delimiter if (*gName == '@') gName++; // Close the current scope, and add a conjunction for the next (if any) if (vxTableName.isValid() && (*gName != '@')) vxTableName += "s "; } // End of WHILE if (vxTableName.isValid()) { if (!*gName) vxTableName += DN_truncated; vxTableName += '}'; } // End of IF } // End of IF // Skip the 'vpath-name' terminator if (*gName == '@') gName++; } // End of IF } // End of IF then else if(vxTableName.isValid()) vxTableName = DN_truncated + vxTableName; return vxTableName; } // End of "UnDecorator" FUNCTION "getVfTableType" inline DName UnDecorator::getVdispMapType(const DName & superType) { DName vdispMapName = superType; vdispMapName += "{for "; vdispMapName += getScope(); vdispMapName += '}'; if (*gName == '@') gName++; return vdispMapName; } #endif // !NO_COMPILER_NAMES inline DName UnDecorator::getExternalDataType(const DName & superType) { // Create an indirect declarator for the the rest DName * pDeclarator = gnew DName(); DName declaration = getDataType(pDeclarator); // Now insert the declarator into the declaration along with its 'storage-convention' *pDeclarator = getStorageConvention() + ' ' + superType; return declaration; } // End of "UnDecorator" FUNCTION "getExternalDataType" inline int UnDecorator::doUnderScore() { return !(disableFlags & UNDNAME_NO_LEADING_UNDERSCORES); } inline int UnDecorator::doMSKeywords() { return !(disableFlags & UNDNAME_NO_MS_KEYWORDS); } inline int UnDecorator::doPtr64() { return !(disableFlags & UNDNAME_NO_PTR64); } inline int UnDecorator::doFunctionReturns() { return !(disableFlags & UNDNAME_NO_FUNCTION_RETURNS); } inline int UnDecorator::doAllocationModel() { return !(disableFlags & UNDNAME_NO_ALLOCATION_MODEL); } inline int UnDecorator::doAllocationLanguage() { return !(disableFlags & UNDNAME_NO_ALLOCATION_LANGUAGE); } #if 0 inline int UnDecorator::doMSThisType() { return !(disableFlags & UNDNAME_NO_MS_THISTYPE); } inline int UnDecorator::doCVThisType() { return !(disableFlags & UNDNAME_NO_CV_THISTYPE); } #endif inline int UnDecorator::doThisTypes() { return ((disableFlags & UNDNAME_NO_THISTYPE) != UNDNAME_NO_THISTYPE); } inline int UnDecorator::doAccessSpecifiers() { return !(disableFlags & UNDNAME_NO_ACCESS_SPECIFIERS); } inline int UnDecorator::doThrowTypes() { return !(disableFlags & UNDNAME_NO_THROW_SIGNATURES); } inline int UnDecorator::doMemberTypes() { return !(disableFlags & UNDNAME_NO_MEMBER_TYPE); } inline int UnDecorator::doReturnUDTModel() { return !(disableFlags & UNDNAME_NO_RETURN_UDT_MODEL); } inline int UnDecorator::do32BitNear() { return !(disableFlags & UNDNAME_32_BIT_DECODE); } inline int UnDecorator::doNameOnly() { return (disableFlags & UNDNAME_NAME_ONLY); } inline int UnDecorator::doTypeOnly() { return (disableFlags & UNDNAME_TYPE_ONLY); } inline int UnDecorator::haveTemplateParameters() { return (disableFlags & UNDNAME_HAVE_PARAMETERS); } inline int UnDecorator::doEcsu() { return !(disableFlags & UNDNAME_NO_ECSU); } inline int UnDecorator::doNoIdentCharCheck() { return (disableFlags & UNDNAME_NO_IDENT_CHAR_CHECK); } inline int UnDecorator::doEllipsis() { return !(disableFlags & UNDNAME_NO_ELLIPSIS); } #if CC_RESTRICTION_SPEC inline int UnDecorator::doRestrictionSpec() { return !(disableFlags & UNDNAME_NO_RESTRICTION_SPEC); } #endif // CC_RESTRICTION_SPEC pcchar_t UnDecorator::UScore(Tokens tok) { #if !VERS_32BIT if (((tok == TOK_nearSp) || (tok == TOK_nearP)) && !do32BitNear()) return tokenTable[tok] + 6; // Skip '__near' #endif if (doUnderScore()) return tokenTable[tok]; else return tokenTable[tok] + 2; } // End of "UnDecorator" FUNCTION "UScore" // Include the string composition support classes. Mostly inline stuff, and // not important to the algorithm. #include "undname.inl"