#include <memory>
#include <unordered_map>
#include <vector>
+#include <list>
#include <iomanip>
#include "torelease.h"
#define MAX_NAMESPACE_LENGTH 1024
+static std::string ConsumeGenericArgs(const std::string &name, std::list<std::string> &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
/**********************************************************************\
* *
\**********************************************************************/
// 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<std::string> &args)
{
HRESULT Status;
DWORD flags;
if (!IsTdNested(flags))
{
+ mdName = ConsumeGenericArgs(mdName, args);
return S_OK;
}
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<std::string> &args)
{
mdName[0] = L'\0';
if ((mb & 0xff000000) != mdtTypeDef
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)
{
{
if (mdClass != mdTypeDefNil && bClassName)
{
- hr = NameForTypeDef(mdClass, pImport, mdName);
+ hr = NameForTypeDef(mdClass, pImport, mdName, args);
mdName += ".";
}
mdName += to_utf8(name/*, size*/);
{
if (mdClass != mdTypeDefNil && bClassName)
{
- hr = NameForTypeDef(mdClass, pImport, mdName);
+ hr = NameForTypeDef(mdClass, pImport, mdName, args);
mdName += ".";
}
mdName += to_utf8(name/*, size*/);
return hr;
}
-// From strike.cpp
-
-HRESULT TypePrinter::AddGenericArgs(ICorDebugType *pType, std::stringstream &ss)
+HRESULT TypePrinter::AddGenericArgs(ICorDebugType *pType, std::list<std::string> &args)
{
ToRelease<ICorDebugTypeEnum> pTypeEnum;
if (SUCCEEDED(pType->EnumerateTypeParameters(&pTypeEnum)))
{
- ULONG numTypes = 0;
+ ULONG fetched = 0;
ToRelease<ICorDebugType> 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<std::string> &args)
+{
+ HRESULT Status;
+
+ ToRelease<ICorDebugILFrame2> pILFrame2;
+ IfFailRet(pFrame->QueryInterface(IID_ICorDebugILFrame2, (LPVOID*) &pILFrame2));
+
+ ToRelease<ICorDebugTypeEnum> pTypeEnum;
+
+ if (SUCCEEDED(pILFrame2->EnumerateTypeParameters(&pTypeEnum)))
+ {
+ ULONG numTypes = 0;
+ ToRelease<ICorDebugType> 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;
return S_OK;
}
+// From strike.cpp
+
HRESULT TypePrinter::GetTypeOfValue(ICorDebugType *pType, std::string &elementType, std::string &arrayType)
{
HRESULT Status = S_OK;
//Defaults in case we fail...
elementType = (corElemType == ELEMENT_TYPE_VALUETYPE) ? "struct" : "class";
+ std::list<std::string> args;
+ AddGenericArgs(pType, args);
+
mdTypeDef typeDef;
ToRelease<ICorDebugClass> pClass;
if(SUCCEEDED(pType->GetClass(&pClass)) && SUCCEEDED(pClass->GetToken(&typeDef)))
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";
ss << name;
}
}
- AddGenericArgs(pType, ss);
elementType = ss.str();
return S_OK;
}
{
HRESULT Status;
- ToRelease<ICorDebugILFrame2> pILFrame2;
- IfFailRet(pFrame->QueryInterface(IID_ICorDebugILFrame2, (LPVOID*) &pILFrame2));
-
ToRelease<ICorDebugFunction> pFunction;
IfFailRet(pFrame->GetFunction(&pFunction));
IfFailRet(pFunction->GetModule(&pModule));
IfFailRet(pFunction->GetToken(&methodDef));
- WCHAR wszModuleName[100];
- ULONG32 cchModuleNameActual;
- IfFailRet(pModule->GetName(_countof(wszModuleName), &cchModuleNameActual, wszModuleName));
-
ToRelease<IUnknown> pMDUnknown;
ToRelease<IMetaDataImport> pMD;
WCHAR szFunctionName[mdNameLen] = {0};
+ ToRelease<IMetaDataImport2> 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<IMetaDataImport2> pMD2;
- IfFailRet(pMDUnknown->QueryInterface(IID_IMetaDataImport2, (LPVOID*) &pMD2));
+ std::string funcName = to_utf8(szFunctionName/*, nameLen*/);
ULONG methodGenericsCount = 0;
HCORENUM hEnum = NULL;
if (methodGenericsCount > 0)
{
- ss << '`' << methodGenericsCount;
+ std::stringstream ss;
+ ss << funcName << '`' << methodGenericsCount;
+ funcName = ss.str();
}
- ToRelease<ICorDebugTypeEnum> pTypeEnum;
+ std::list<std::string> args;
+ AddGenericArgs(pFrame, args);
- if (SUCCEEDED(pILFrame2->EnumerateTypeParameters(&pTypeEnum)))
+ std::stringstream ss;
+ if (memTypeDef != mdTypeDefNil)
{
- ULONG numTypes = 0;
- ToRelease<ICorDebugType> 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();