From 626253ae80e4987b51dea39ef7b3ac44616fe552 Mon Sep 17 00:00:00 2001 From: Igor Kulaychuk Date: Mon, 24 Jul 2017 04:07:20 +0300 Subject: [PATCH] Add support for array types in generic parameters in expression evaluation --- src/debug/netcoredbg/expr.cpp | 154 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 133 insertions(+), 21 deletions(-) diff --git a/src/debug/netcoredbg/expr.cpp b/src/debug/netcoredbg/expr.cpp index 77f3994..b40abc1 100644 --- a/src/debug/netcoredbg/expr.cpp +++ b/src/debug/netcoredbg/expr.cpp @@ -10,6 +10,7 @@ #include #include +#include "debugger.h" #include "typeprinter.h" #include "modules.h" #include "valuewalk.h" @@ -217,6 +218,59 @@ static std::vector ParseExpression(const std::string &expression) return result; } +static std::vector ParseType(const std::string &expression, std::vector &ranks) +{ + std::vector result; + int paramDepth = 0; + + result.push_back(""); + + for (char c : expression) + { + switch(c) + { + case '.': + if (paramDepth == 0) + { + result.push_back(""); + continue; + } + break; + case '[': + if (paramDepth == 0) + { + ranks.push_back(1); + continue; + } + break; + case ']': + if (paramDepth == 0) + continue; + break; + case ',': + if (paramDepth == 0) + { + if (!ranks.empty()) + ranks.back()++; + continue; + } + break; + case '<': + paramDepth++; + break; + case '>': + paramDepth--; + break; + case ' ': + continue; + default: + break; + } + result.back() += c; + } + return result; +} + static std::vector ParseGenericParams(const std::string &part, std::string &typeName) { std::vector result; @@ -229,6 +283,7 @@ static std::vector ParseGenericParams(const std::string &part, std: } int paramDepth = 0; + bool inArray = false; result.push_back(""); @@ -238,12 +293,18 @@ static std::vector ParseGenericParams(const std::string &part, std: switch(c) { case ',': - if (paramDepth == 1) + if (paramDepth == 1 && !inArray) { result.push_back(""); continue; } break; + case '[': + inArray = true; + break; + case ']': + inArray = false; + break; case '<': paramDepth++; if (paramDepth == 1) continue; @@ -317,15 +378,6 @@ HRESULT FindTypeInModule(ICorDebugModule *pModule, const std::vector &parts, int &nextPart, ICorDebugModule *pModule, ICorDebugType **ppType, ICorDebugModule **ppModule = nullptr); - -HRESULT GetType(const std::string &typeName, ICorDebugType **ppType) -{ - std::vector classParts = ParseExpression(typeName); - int nextClassPart = 0; - return FindType(classParts, nextClassPart, nullptr, ppType); -} - static std::string RenameType(const std::string &shortTypeName) { static const std::unordered_map short2long = { @@ -351,19 +403,69 @@ static std::string RenameType(const std::string &shortTypeName) return renamed != short2long.end() ? renamed->second : shortTypeName; } -HRESULT ResolveParameters(const std::vector ¶ms, std::vector< ToRelease > &types) +HRESULT FindType( + const std::vector &parts, + int &nextPart, ICorDebugThread *pThread, + ICorDebugModule *pModule, + ICorDebugType **ppType, + ICorDebugModule **ppModule = nullptr); + +HRESULT GetType(const std::string &typeName, + ICorDebugThread *pThread, + ICorDebugType **ppType) +{ + HRESULT Status; + std::vector ranks; + std::vector classParts = ParseType(typeName, ranks); + if (classParts.size() == 1) + classParts[0] = RenameType(classParts[0]); + + ToRelease pType; + int nextClassPart = 0; + IfFailRet(FindType(classParts, nextClassPart, pThread, nullptr, &pType)); + + if (!ranks.empty()) + { + ToRelease pAppDomain2; + ToRelease pAppDomain; + IfFailRet(pThread->GetAppDomain(&pAppDomain)); + IfFailRet(pAppDomain->QueryInterface(IID_ICorDebugAppDomain2, (LPVOID*) &pAppDomain2)); + + for (auto irank = ranks.rbegin(); irank != ranks.rend(); ++irank) + { + ToRelease pElementType(std::move(pType)); + IfFailRet(pAppDomain2->GetArrayOrPointerType( + *irank > 1 ? ELEMENT_TYPE_ARRAY : ELEMENT_TYPE_SZARRAY, + *irank, + pElementType, + &pType)); + } + } + + *ppType = pType.Detach(); + return S_OK; +} + +HRESULT ResolveParameters(const std::vector ¶ms, + ICorDebugThread *pThread, + std::vector< ToRelease > &types) { HRESULT Status; for (auto &p : params) { ICorDebugType *tmpType; - IfFailRet(GetType(RenameType(p), &tmpType)); + IfFailRet(GetType(p, pThread, &tmpType)); types.emplace_back(tmpType); } return S_OK; } -HRESULT FindType(const std::vector &parts, int &nextPart, ICorDebugModule *pModule, ICorDebugType **ppType, ICorDebugModule **ppModule) +HRESULT FindType(const std::vector &parts, + int &nextPart, + ICorDebugThread *pThread, + ICorDebugModule *pModule, + ICorDebugType **ppType, + ICorDebugModule **ppModule) { HRESULT Status; @@ -397,7 +499,7 @@ HRESULT FindType(const std::vector &parts, int &nextPart, ICorDebug std::vector params = GatherParameters(parts, nextPart); std::vector< ToRelease > types; - IfFailRet(ResolveParameters(params, types)); + IfFailRet(ResolveParameters(params, pThread, types)); ToRelease pClass; IfFailRet(pTypeModule->GetClassFromToken(typeToken, &pClass)); @@ -432,22 +534,27 @@ HRESULT FindType(const std::vector &parts, int &nextPart, ICorDebug return S_OK; } -static HRESULT FollowNested(ICorDebugThread *pThread, ICorDebugILFrame *pILFrame, const std::string &methodClass, const std::vector &parts, ICorDebugValue **ppResult) +static HRESULT FollowNested(ICorDebugThread *pThread, + ICorDebugILFrame *pILFrame, + const std::string &methodClass, + const std::vector &parts, + ICorDebugValue **ppResult) { HRESULT Status; - std::vector classParts = ParseExpression(methodClass); + std::vector ranks; + std::vector classParts = ParseType(methodClass, ranks); int nextClassPart = 0; ToRelease pType; ToRelease pModule; - IfFailRet(FindType(classParts, nextClassPart, nullptr, &pType, &pModule)); + IfFailRet(FindType(classParts, nextClassPart, pThread, nullptr, &pType, &pModule)); while (!classParts.empty()) { ToRelease pEnclosingType(std::move(pType)); int nextClassPart = 0; - if (FAILED(FindType(classParts, nextClassPart, pModule, &pType))) + if (FAILED(FindType(classParts, nextClassPart, pThread, pModule, &pType))) break; ToRelease pTypeValue; @@ -462,7 +569,10 @@ static HRESULT FollowNested(ICorDebugThread *pThread, ICorDebugILFrame *pILFrame return E_FAIL; } -HRESULT EvalExpr(ICorDebugThread *pThread, ICorDebugFrame *pFrame, const std::string &expression, ICorDebugValue **ppResult) +HRESULT EvalExpr(ICorDebugThread *pThread, + ICorDebugFrame *pFrame, + const std::string &expression, + ICorDebugValue **ppResult) { HRESULT Status; @@ -486,7 +596,9 @@ HRESULT EvalExpr(ICorDebugThread *pThread, ICorDebugFrame *pFrame, const std::st } else { - IfFailRet(WalkStackVars(pFrame, [&](ICorDebugILFrame *pILFrame, ICorDebugValue *pValue, const std::string &name) -> HRESULT + IfFailRet(WalkStackVars(pFrame, [&](ICorDebugILFrame *pILFrame, + ICorDebugValue *pValue, + const std::string &name) -> HRESULT { if (pResultValue) return S_OK; // TODO: Create a fast way to exit @@ -543,7 +655,7 @@ HRESULT EvalExpr(ICorDebugThread *pThread, ICorDebugFrame *pFrame, const std::st else { ToRelease pType; - IfFailRet(FindType(parts, nextPart, nullptr, &pType)); + IfFailRet(FindType(parts, nextPart, pThread, nullptr, &pType)); IfFailRet(EvalObjectNoConstructor(pThread, pType, &pResultValue)); followMode = FollowStatic; } -- 2.7.4