From 9954d1e3b384b132d38798941be0bc0589b6013f Mon Sep 17 00:00:00 2001 From: Igor Kulaychuk Date: Tue, 11 Jul 2017 16:14:27 +0300 Subject: [PATCH] Enable generics pretty printing --- src/debug/debugger/main.cpp | 1 + src/debug/debugger/typeprinter.cpp | 169 ++++++++++++++++++++++++------------- src/debug/debugger/typeprinter.h | 13 ++- src/debug/debugger/valueprint.cpp | 1 + src/debug/debugger/valuewalk.cpp | 1 + src/debug/debugger/varobj.cpp | 1 + 6 files changed, 123 insertions(+), 63 deletions(-) diff --git a/src/debug/debugger/main.cpp b/src/debug/debugger/main.cpp index df187bb..974a9d6 100644 --- a/src/debug/debugger/main.cpp +++ b/src/debug/debugger/main.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include diff --git a/src/debug/debugger/typeprinter.cpp b/src/debug/debugger/typeprinter.cpp index 4ff06a5..2f2c961 100644 --- a/src/debug/debugger/typeprinter.cpp +++ b/src/debug/debugger/typeprinter.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "torelease.h" @@ -28,6 +29,49 @@ typedef uintptr_t TADDR; #define MAX_NAMESPACE_LENGTH 1024 +static std::string ConsumeGenericArgs(const std::string &name, std::list &args) +{ + if (args.empty()) + return name; + + std::size_t offset = name.find_last_not_of("0123456789"); + + if (offset == std::string::npos || offset == name.size() - 1 || name.at(offset) != '`') + return name; + + unsigned long numArgs = 0; + try { + numArgs = std::stoul(name.substr(offset + 1)); + } + catch(std::invalid_argument e) + { + return name; + } + catch (std::out_of_range e) + { + return name; + } + + if (numArgs == 0 || numArgs > args.size()) + { + return name; + } + + std::stringstream ss; + ss << name.substr(0, offset); + ss << "<"; + const char *sep = ""; + while (numArgs--) + { + ss << sep; + sep = ", "; + ss << args.front(); + args.pop_front(); + } + ss << ">"; + return ss.str(); +} + // From metadata.cpp /**********************************************************************\ @@ -38,7 +82,11 @@ typedef uintptr_t TADDR; * * \**********************************************************************/ // Caller should guard against exception -HRESULT TypePrinter::NameForTypeDef(mdTypeDef tkTypeDef, IMetaDataImport *pImport, std::string &mdName) +HRESULT TypePrinter::NameForTypeDef( + mdTypeDef tkTypeDef, + IMetaDataImport *pImport, + std::string &mdName, + std::list &args) { HRESULT Status; DWORD flags; @@ -50,6 +98,7 @@ HRESULT TypePrinter::NameForTypeDef(mdTypeDef tkTypeDef, IMetaDataImport *pImpor if (!IsTdNested(flags)) { + mdName = ConsumeGenericArgs(mdName, args); return S_OK; } @@ -57,14 +106,18 @@ HRESULT TypePrinter::NameForTypeDef(mdTypeDef tkTypeDef, IMetaDataImport *pImpor IfFailRet(pImport->GetNestedClassProps(tkTypeDef, &tkEnclosingClass)); std::string enclosingName; - IfFailRet(NameForTypeDef(tkEnclosingClass, pImport, enclosingName)); + IfFailRet(NameForTypeDef(tkEnclosingClass, pImport, enclosingName, args)); - mdName = enclosingName + "+" + mdName; + mdName = enclosingName + "." + ConsumeGenericArgs(mdName, args); return S_OK; } -HRESULT TypePrinter::NameForToken(mdTypeDef mb, IMetaDataImport *pImport, std::string &mdName, bool bClassName) +HRESULT TypePrinter::NameForToken(mdTypeDef mb, + IMetaDataImport *pImport, + std::string &mdName, + bool bClassName, + std::list &args) { mdName[0] = L'\0'; if ((mb & 0xff000000) != mdtTypeDef @@ -82,7 +135,7 @@ HRESULT TypePrinter::NameForToken(mdTypeDef mb, IMetaDataImport *pImport, std::s WCHAR name[MAX_CLASSNAME_LENGTH]; if ((mb & 0xff000000) == mdtTypeDef) { - hr = NameForTypeDef(mb, pImport, mdName); + hr = NameForTypeDef(mb, pImport, mdName, args); } else if ((mb & 0xff000000) == mdtFieldDef) { @@ -96,7 +149,7 @@ HRESULT TypePrinter::NameForToken(mdTypeDef mb, IMetaDataImport *pImport, std::s { if (mdClass != mdTypeDefNil && bClassName) { - hr = NameForTypeDef(mdClass, pImport, mdName); + hr = NameForTypeDef(mdClass, pImport, mdName, args); mdName += "."; } mdName += to_utf8(name/*, size*/); @@ -113,7 +166,7 @@ HRESULT TypePrinter::NameForToken(mdTypeDef mb, IMetaDataImport *pImport, std::s { if (mdClass != mdTypeDefNil && bClassName) { - hr = NameForTypeDef(mdClass, pImport, mdName); + hr = NameForTypeDef(mdClass, pImport, mdName, args); mdName += "."; } mdName += to_utf8(name/*, size*/); @@ -133,30 +186,46 @@ HRESULT TypePrinter::NameForToken(mdTypeDef mb, IMetaDataImport *pImport, std::s return hr; } -// From strike.cpp - -HRESULT TypePrinter::AddGenericArgs(ICorDebugType *pType, std::stringstream &ss) +HRESULT TypePrinter::AddGenericArgs(ICorDebugType *pType, std::list &args) { ToRelease pTypeEnum; if (SUCCEEDED(pType->EnumerateTypeParameters(&pTypeEnum))) { - ULONG numTypes = 0; + ULONG fetched = 0; ToRelease pCurrentTypeParam; - bool isFirst = true; + while (SUCCEEDED(pTypeEnum->Next(1, &pCurrentTypeParam, &fetched)) && fetched == 1) + { + std::string name; + GetTypeOfValue(pCurrentTypeParam, name); + args.emplace_back(name); + } + } + + return S_OK; +} + +HRESULT TypePrinter::AddGenericArgs(ICorDebugFrame *pFrame, std::list &args) +{ + HRESULT Status; + + ToRelease pILFrame2; + IfFailRet(pFrame->QueryInterface(IID_ICorDebugILFrame2, (LPVOID*) &pILFrame2)); + + ToRelease pTypeEnum; + + if (SUCCEEDED(pILFrame2->EnumerateTypeParameters(&pTypeEnum))) + { + ULONG numTypes = 0; + ToRelease pCurrentTypeParam; while (SUCCEEDED(pTypeEnum->Next(1, &pCurrentTypeParam, &numTypes)) && numTypes == 1) { - ss << (isFirst ? "<" : ","); - isFirst = false; - std::string name; GetTypeOfValue(pCurrentTypeParam, name); - ss << name; + args.emplace_back(name); } - if(!isFirst) - ss << ">"; } return S_OK; @@ -179,6 +248,8 @@ HRESULT TypePrinter::GetTypeOfValue(ICorDebugValue *pValue, std::string &output) return S_OK; } +// From strike.cpp + HRESULT TypePrinter::GetTypeOfValue(ICorDebugType *pType, std::string &elementType, std::string &arrayType) { HRESULT Status = S_OK; @@ -218,6 +289,9 @@ HRESULT TypePrinter::GetTypeOfValue(ICorDebugType *pType, std::string &elementTy //Defaults in case we fail... elementType = (corElemType == ELEMENT_TYPE_VALUETYPE) ? "struct" : "class"; + std::list args; + AddGenericArgs(pType, args); + mdTypeDef typeDef; ToRelease pClass; if(SUCCEEDED(pType->GetClass(&pClass)) && SUCCEEDED(pClass->GetToken(&typeDef))) @@ -232,7 +306,7 @@ HRESULT TypePrinter::GetTypeOfValue(ICorDebugType *pType, std::string &elementTy std::string name; - if(SUCCEEDED(NameForToken(TokenFromRid(typeDef, mdtTypeDef), pMD, name, false))) + if(SUCCEEDED(NameForToken(TokenFromRid(typeDef, mdtTypeDef), pMD, name, false, args))) { if (name == "System.Decimal") ss << "decimal"; @@ -240,7 +314,6 @@ HRESULT TypePrinter::GetTypeOfValue(ICorDebugType *pType, std::string &elementTy ss << name; } } - AddGenericArgs(pType, ss); elementType = ss.str(); return S_OK; } @@ -365,9 +438,6 @@ HRESULT TypePrinter::GetMethodName(ICorDebugFrame *pFrame, std::string &output) { HRESULT Status; - ToRelease pILFrame2; - IfFailRet(pFrame->QueryInterface(IID_ICorDebugILFrame2, (LPVOID*) &pILFrame2)); - ToRelease pFunction; IfFailRet(pFrame->GetFunction(&pFunction)); @@ -378,10 +448,6 @@ HRESULT TypePrinter::GetMethodName(ICorDebugFrame *pFrame, std::string &output) IfFailRet(pFunction->GetModule(&pModule)); IfFailRet(pFunction->GetToken(&methodDef)); - WCHAR wszModuleName[100]; - ULONG32 cchModuleNameActual; - IfFailRet(pModule->GetName(_countof(wszModuleName), &cchModuleNameActual, wszModuleName)); - ToRelease pMDUnknown; ToRelease pMD; @@ -402,26 +468,14 @@ HRESULT TypePrinter::GetMethodName(ICorDebugFrame *pFrame, std::string &output) WCHAR szFunctionName[mdNameLen] = {0}; + ToRelease pMD2; + IfFailRet(pMDUnknown->QueryInterface(IID_IMetaDataImport2, (LPVOID*) &pMD2)); + hr = pMD->GetMethodProps(methodDef, &memTypeDef, szFunctionName, _countof(szFunctionName), &nameLen, &flags, &pbSigBlob, &ulSigBlob, &ulCodeRVA, &ulImplFlags); - std::stringstream ss; - - if (memTypeDef != mdTypeDefNil) - { - std::string name; - hr = NameForTypeDef(memTypeDef, pMD, name); - if (SUCCEEDED(hr)) - { - ss << name << "."; - } - } - - ss << to_utf8(szFunctionName/*, nameLen*/); - - ToRelease pMD2; - IfFailRet(pMDUnknown->QueryInterface(IID_IMetaDataImport2, (LPVOID*) &pMD2)); + std::string funcName = to_utf8(szFunctionName/*, nameLen*/); ULONG methodGenericsCount = 0; HCORENUM hEnum = NULL; @@ -435,31 +489,26 @@ HRESULT TypePrinter::GetMethodName(ICorDebugFrame *pFrame, std::string &output) if (methodGenericsCount > 0) { - ss << '`' << methodGenericsCount; + std::stringstream ss; + ss << funcName << '`' << methodGenericsCount; + funcName = ss.str(); } - ToRelease pTypeEnum; + std::list args; + AddGenericArgs(pFrame, args); - if (SUCCEEDED(pILFrame2->EnumerateTypeParameters(&pTypeEnum))) + std::stringstream ss; + if (memTypeDef != mdTypeDefNil) { - ULONG numTypes = 0; - ToRelease pCurrentTypeParam; - - bool isFirst = true; - - while (SUCCEEDED(pTypeEnum->Next(1, &pCurrentTypeParam, &numTypes)) && numTypes == 1) + std::string name; + hr = NameForTypeDef(memTypeDef, pMD, name, args); + if (SUCCEEDED(hr)) { - ss << (isFirst ? "<" : ","); - isFirst = false; - - std::string name; - GetTypeOfValue(pCurrentTypeParam, name); - ss << name; + ss << name << "."; } - if(!isFirst) - ss << ">"; } + ss << ConsumeGenericArgs(funcName, args); ss << "()"; output = ss.str(); diff --git a/src/debug/debugger/typeprinter.h b/src/debug/debugger/typeprinter.h index 79a9fe3..2dcb342 100644 --- a/src/debug/debugger/typeprinter.h +++ b/src/debug/debugger/typeprinter.h @@ -1,8 +1,15 @@ +namespace std { +class list; +} + class TypePrinter { - static HRESULT NameForTypeDef(mdTypeDef tkTypeDef, IMetaDataImport *pImport, std::string &mdName); - static HRESULT NameForToken(mdTypeDef mb, IMetaDataImport *pImport, std::string &mdName, bool bClassName); - static HRESULT AddGenericArgs(ICorDebugType *pType, std::stringstream &ss); + static HRESULT NameForTypeDef(mdTypeDef tkTypeDef, IMetaDataImport *pImport, std::string &mdName, + std::list &args); + static HRESULT NameForToken(mdTypeDef mb, IMetaDataImport *pImport, std::string &mdName, bool bClassName, + std::list &args); + static HRESULT AddGenericArgs(ICorDebugType *pType, std::list &args); + static HRESULT AddGenericArgs(ICorDebugFrame *pFrame, std::list &args); static HRESULT GetTypeOfValue(ICorDebugType *pType, std::string &elementType, std::string &arrayType); public: static HRESULT GetTypeOfValue(ICorDebugType *pType, std::string &output); diff --git a/src/debug/debugger/valueprint.cpp b/src/debug/debugger/valueprint.cpp index c0856d3..8cd3a5d 100644 --- a/src/debug/debugger/valueprint.cpp +++ b/src/debug/debugger/valueprint.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "torelease.h" diff --git a/src/debug/debugger/valuewalk.cpp b/src/debug/debugger/valuewalk.cpp index 06bbdd9..f6d9d93 100644 --- a/src/debug/debugger/valuewalk.cpp +++ b/src/debug/debugger/valuewalk.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "torelease.h" diff --git a/src/debug/debugger/varobj.cpp b/src/debug/debugger/varobj.cpp index 340e112..32929e6 100644 --- a/src/debug/debugger/varobj.cpp +++ b/src/debug/debugger/varobj.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "torelease.h" -- 2.7.4