return Status;
}
- HRESULT GetIndexesFromStack(std::vector<ULONG32> &indexes, int dimension, std::list<EvalStackEntry> &evalStack, EvalData &ed, std::string &output)
- {
- HRESULT Status;
-
- for (int32_t i = 0; i < dimension; i++)
- {
- ToRelease<ICorDebugValue> 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;
HRESULT ElementBindingExpression(std::list<EvalStackEntry> &evalStack, PVOID pArguments, std::string &output, EvalData &ed)
{
int32_t Int = ((FormatFI*)pArguments)->Int;
-
HRESULT Status;
- std::vector<ULONG32> indexes;
- IfFailRet(GetIndexesFromStack(indexes, Int, evalStack, ed, output));
+ std::vector<ToRelease<ICorDebugValue>> indexvalues(Int);
+
+ for (int32_t i = Int - 1; i >= 0; i--)
+ {
+ ToRelease<ICorDebugValue> iCorValue;
+ IfFailRet(GetFrontStackEntryValue(&indexvalues[i], nullptr, evalStack, ed, output));
+ evalStack.pop_front();
+ }
if (evalStack.front().preventBinding)
return S_OK;
- ToRelease<ICorDebugValue> iCorArrayValue;
+ ToRelease<ICorDebugValue> iCorObjectValue;
std::unique_ptr<Evaluator::SetterData> setterData;
- IfFailRet(GetFrontStackEntryValue(&iCorArrayValue, &setterData, evalStack, ed, output));
+ IfFailRet(GetFrontStackEntryValue(&iCorObjectValue, &setterData, evalStack, ed, output));
ToRelease<ICorDebugReferenceValue> pReferenceValue;
- IfFailRet(iCorArrayValue->QueryInterface(IID_ICorDebugReferenceValue, (LPVOID*) &pReferenceValue));
+ IfFailRet(iCorObjectValue->QueryInterface(IID_ICorDebugReferenceValue, (LPVOID*) &pReferenceValue));
BOOL isNull = FALSE;
IfFailRet(pReferenceValue->IsNull(&isNull));
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<ICorDebugValue> iCorRealValue;
+ CorElementType elemType;
+ IfFailRet(GetRealValueWithType(iCorObjectValue, &iCorRealValue, &elemType));
+ std::vector<ULONG32> 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<Evaluator::ArgElementType> funcArgs(Int);
+ for (int32_t i = 0; i < Int; ++i)
+ {
+ ToRelease<ICorDebugValue> 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<ICorDebugFunction> iCorFunc;
+ ed.pEvaluator->WalkMethods(iCorObjectValue, [&](
+ bool,
+ const std::string &methodName,
+ Evaluator::ReturnElementType& retType,
+ std::vector<Evaluator::ArgElementType> &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<ICorDebugValue*> 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<ICorDebugValue2> iCorValue2;
+ IfFailRet(iCorObjectValue->QueryInterface(IID_ICorDebugValue2, (LPVOID *) &iCorValue2));
+ ToRelease<ICorDebugType> 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<EvalStackEntry> &evalStack, PVOID pArguments, std::string &output, EvalData &ed)
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;
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__");
});
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;
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__");
});