From: Oleg Lekarev Date: Tue, 23 Aug 2022 15:28:41 +0000 (+0300) Subject: Indexers for nullable generic classes/standard containers evaluation support added. X-Git-Tag: submit/tizen/20220829.140311~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=dc0a96ea84ea53fa6c5678ed0cbf96e6ae091b26;p=sdk%2Ftools%2Fnetcoredbg.git Indexers for nullable generic classes/standard containers evaluation support added. --- diff --git a/src/debugger/evalstackmachine.cpp b/src/debugger/evalstackmachine.cpp index 4a9e447..ab22691 100644 --- a/src/debugger/evalstackmachine.cpp +++ b/src/debugger/evalstackmachine.cpp @@ -342,27 +342,6 @@ namespace return Status; } - HRESULT GetIndexesFromStack(std::vector &indexes, int dimension, std::list &evalStack, EvalData &ed, std::string &output) - { - HRESULT Status; - - for (int32_t i = 0; i < dimension; i++) - { - ToRelease iCorValue; - IfFailRet(GetFrontStackEntryValue(&iCorValue, nullptr, evalStack, ed, output)); - evalStack.pop_front(); - - // TODO implicitly convert iCorValue to int, if type not int - // at this moment GetElementIndex() work with integer types only - - ULONG32 result_index = 0; - IfFailRet(GetElementIndex(iCorValue, result_index)); - indexes.insert(indexes.begin(), result_index); - } - - return S_OK; - } - HRESULT GetArgData(ICorDebugValue *pTypeValue, std::string &typeName, CorElementType &elemType) { HRESULT Status; @@ -1311,20 +1290,25 @@ namespace HRESULT ElementBindingExpression(std::list &evalStack, PVOID pArguments, std::string &output, EvalData &ed) { int32_t Int = ((FormatFI*)pArguments)->Int; - HRESULT Status; - std::vector indexes; - IfFailRet(GetIndexesFromStack(indexes, Int, evalStack, ed, output)); + std::vector> indexvalues(Int); + + for (int32_t i = Int - 1; i >= 0; i--) + { + ToRelease iCorValue; + IfFailRet(GetFrontStackEntryValue(&indexvalues[i], nullptr, evalStack, ed, output)); + evalStack.pop_front(); + } if (evalStack.front().preventBinding) return S_OK; - ToRelease iCorArrayValue; + ToRelease iCorObjectValue; std::unique_ptr setterData; - IfFailRet(GetFrontStackEntryValue(&iCorArrayValue, &setterData, evalStack, ed, output)); + IfFailRet(GetFrontStackEntryValue(&iCorObjectValue, &setterData, evalStack, ed, output)); ToRelease pReferenceValue; - IfFailRet(iCorArrayValue->QueryInterface(IID_ICorDebugReferenceValue, (LPVOID*) &pReferenceValue)); + IfFailRet(iCorObjectValue->QueryInterface(IID_ICorDebugReferenceValue, (LPVOID*) &pReferenceValue)); BOOL isNull = FALSE; IfFailRet(pReferenceValue->IsNull(&isNull)); @@ -1334,10 +1318,79 @@ namespace return S_OK; } - evalStack.front().iCorValue.Free(); - evalStack.front().identifiers.clear(); - evalStack.front().setterData = std::move(setterData); - return ed.pEvaluator->GetElement(iCorArrayValue, indexes, &evalStack.front().iCorValue); + ToRelease iCorRealValue; + CorElementType elemType; + IfFailRet(GetRealValueWithType(iCorObjectValue, &iCorRealValue, &elemType)); + std::vector indexes; + + if (elemType == ELEMENT_TYPE_SZARRAY || elemType == ELEMENT_TYPE_ARRAY) { + for (int32_t i = Int - 1; i >= 0; i--) + { + ULONG32 result_index = 0; + // TODO implicitly convert iCorValue to int, if type not int + // at this moment GetElementIndex() work with integer types only + IfFailRet(GetElementIndex(indexvalues[i], result_index)); + indexes.insert(indexes.begin(), result_index); + } + evalStack.front().iCorValue.Free(); + evalStack.front().identifiers.clear(); + evalStack.front().setterData = std::move(setterData); + Status = ed.pEvaluator->GetElement(iCorObjectValue, indexes, &evalStack.front().iCorValue); + } else { + std::vector funcArgs(Int); + for (int32_t i = 0; i < Int; ++i) + { + ToRelease iCorValueArg; + IfFailRet(DereferenceAndUnboxValue(indexvalues[i].GetPtr(), &iCorValueArg, nullptr)); + IfFailRet(iCorValueArg->GetType(&funcArgs[i].corType)); + + if (funcArgs[i].corType == ELEMENT_TYPE_VALUETYPE || funcArgs[i].corType == ELEMENT_TYPE_CLASS) + IfFailRet(TypePrinter::NameForTypeByValue(iCorValueArg, funcArgs[i].typeName)); + } + + ToRelease iCorFunc; + ed.pEvaluator->WalkMethods(iCorObjectValue, [&]( + bool, + const std::string &methodName, + Evaluator::ReturnElementType& retType, + std::vector &methodArgs, + Evaluator::GetFunctionCallback getFunction) + { + std::string name = "get_Item"; + std::size_t found = methodName.rfind(name); + if (retType.corType == ELEMENT_TYPE_VOID || found == std::string::npos || found != methodName.length() - name.length() || funcArgs.size() != methodArgs.size()) + return S_OK; // Return with success to continue walk. + + for (size_t i = 0; i < funcArgs.size(); ++i) + { + if (funcArgs[i].corType != methodArgs[i].corType || + funcArgs[i].typeName != methodArgs[i].typeName) + return S_OK; + } + IfFailRet(getFunction(&iCorFunc)); + return E_ABORT; // Fast exit from cycle, since we already found iCorFunc. + }); + if (!iCorFunc) + return E_INVALIDARG; + evalStack.front().ResetEntry(); + std::vector iCorValueArgs; + iCorValueArgs.reserve(Int+1); + + iCorValueArgs.emplace_back(iCorObjectValue.GetPtr()); + + for (int32_t i = 0; i < Int; i++) + { + iCorValueArgs.emplace_back(indexvalues[i].GetPtr()); + } + + ToRelease iCorValue2; + IfFailRet(iCorObjectValue->QueryInterface(IID_ICorDebugValue2, (LPVOID *) &iCorValue2)); + ToRelease iCorType; + IfFailRet(iCorValue2->GetExactType(&iCorType)); + + Status = ed.pEvalHelpers->EvalFunction(ed.pThread, iCorFunc, iCorType.GetRef(), 1, iCorValueArgs.data(), Int + 1, &evalStack.front().iCorValue, ed.evalFlags); + } + return Status; } HRESULT NumericLiteralExpression(std::list &evalStack, PVOID pArguments, std::string &output, EvalData &ed) diff --git a/test-suite/MITestEvalArraysIndexers/Program.cs b/test-suite/MITestEvalArraysIndexers/Program.cs index a2d2548..94d6131 100644 --- a/test-suite/MITestEvalArraysIndexers/Program.cs +++ b/test-suite/MITestEvalArraysIndexers/Program.cs @@ -325,6 +325,9 @@ namespace MITestEvalArraysIndexers MyString[] myStrings = new MyString[6] {new MyString("zero"), new MyString("one"), new MyString("two"), new MyString("three"), new MyString("four"), new MyString("five")}; + SimpleInt sinull; + SimpleInt? siq; + int i0 = 0; int i1 = 1; int i2 = 2; @@ -654,6 +657,14 @@ namespace MITestEvalArraysIndexers Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "dictmsmi[\\\"a string\\\"]", "Error: 0x80070057"); Context.GetAndCheckValue(@"__FILE__:__LINE__", "{System.Collections.Generic.KeyNotFoundException}", "System.Collections.Generic.KeyNotFoundException", "dictmsmi[myStrings[5]]"); + // check nullables + Context.GetAndCheckValue(@"__FILE__:__LINE__", "null", "MITestEvalArraysIndexers.SimpleInt", "sinull"); + Context.GetAndCheckValue(@"__FILE__:__LINE__", "{System.NullReferenceException}", "System.NullReferenceException", "sinull[0]"); + Context.GetAndCheckValue(@"__FILE__:__LINE__", "null", "MITestEvalArraysIndexers.SimpleInt", "sinull?[0]"); + Context.GetAndCheckValue(@"__FILE__:__LINE__", "null", "MITestEvalArraysIndexers.SimpleInt", "siq"); + Context.GetAndCheckValue(@"__FILE__:__LINE__", "{System.NullReferenceException}", "System.NullReferenceException", "siq[0]"); + Context.GetAndCheckValue(@"__FILE__:__LINE__", "null", "MITestEvalArraysIndexers.SimpleInt", "siq?[0]"); + Context.Continue(@"__FILE__:__LINE__"); }); diff --git a/test-suite/VSCodeTestEvalArraysIndexers/Program.cs b/test-suite/VSCodeTestEvalArraysIndexers/Program.cs index 31e1e8e..73c20d1 100644 --- a/test-suite/VSCodeTestEvalArraysIndexers/Program.cs +++ b/test-suite/VSCodeTestEvalArraysIndexers/Program.cs @@ -378,6 +378,9 @@ namespace VSCodeTestEvalArraysIndexers MyString[] myStrings = new MyString[6] {new MyString("zero"), new MyString("one"), new MyString("two"), new MyString("three"), new MyString("four"), new MyString("five")}; + SimpleInt sinull; + SimpleInt? siq; + int i0 = 0; int i1 = 1; int i2 = 2; @@ -708,6 +711,14 @@ namespace VSCodeTestEvalArraysIndexers Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "dictmsmi[\"a string\"]", "error: 0x80070057"); Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "{System.Collections.Generic.KeyNotFoundException}", "System.Collections.Generic.KeyNotFoundException", "dictmsmi[myStrings[5]]"); + // check nullables + Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "null", "VSCodeTestEvalArraysIndexers.SimpleInt", "sinull"); + Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "{System.NullReferenceException}", "System.NullReferenceException", "sinull[0]"); + Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "null", "VSCodeTestEvalArraysIndexers.SimpleInt", "sinull?[0]"); + Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "null", "VSCodeTestEvalArraysIndexers.SimpleInt", "siq"); + Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "{System.NullReferenceException}", "System.NullReferenceException", "siq[0]"); + Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "null", "VSCodeTestEvalArraysIndexers.SimpleInt", "siq?[0]"); + Context.Continue(@"__FILE__:__LINE__"); });