return E_INVALIDARG;
HRESULT Status;
+ bool idsEmpty = false;
+ bool isInstance = true;
std::vector<ToRelease<ICorDebugValue>> iCorArgs(Int);
for (int32_t i = Int - 1; i >= 0; i--)
{
evalStack.front().identifiers.pop_back();
if (!evalStack.front().iCorValue && evalStack.front().identifiers.empty())
- evalStack.front().identifiers.emplace_back("this");
+ {
+ std::string methodClass;
+ idsEmpty = true;
+ IfFailRet(ed.pEvaluator->GetMethodClass(ed.pThread, ed.frameLevel, methodClass, isInstance));
+ if (isInstance)
+ {
+ evalStack.front().identifiers.emplace_back("this");
+ }
+ else
+ {
+ // here we add a full qualified "path" separated with dots (aka Class.Subclass.Subclass ..etc)
+ // although <identifiers> usually contains a vector of components of the full name qualification
+ // Anyway, our added component will be correctly processed by Evaluator::ResolveIdentifiers() for
+ // that case as it seals all the qualification components into one with dots before using them.
+ evalStack.front().identifiers.emplace_back(methodClass);
+ }
+ }
ToRelease<ICorDebugValue> iCorValue;
ToRelease<ICorDebugType> iCorType;
std::vector<Evaluator::ArgElementType> funcArgs(Int);
for (int32_t i = 0; i < Int; ++i)
{
- ToRelease<ICorDebugValue> iCorValue;
- IfFailRet(DereferenceAndUnboxValue(iCorArgs[i].GetPtr(), &iCorValue, nullptr));
- IfFailRet(iCorValue->GetType(&funcArgs[i].corType));
+ ToRelease<ICorDebugValue> iCorValueArg;
+ IfFailRet(DereferenceAndUnboxValue(iCorArgs[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(iCorValue, funcArgs[i].typeName));
+ IfFailRet(TypePrinter::NameForTypeByValue(iCorValueArg, funcArgs[i].typeName));
}
ToRelease<ICorDebugFunction> iCorFunc;
std::vector<Evaluator::ArgElementType> &methodArgs,
Evaluator::GetFunctionCallback getFunction)
{
- if ((searchStatic && !is_static) || (!searchStatic && is_static) ||
+ if ( (searchStatic && !is_static) || (!searchStatic && is_static && !idsEmpty) ||
funcArgs.size() != methodArgs.size() || funcName != methodName)
return S_OK;
}
IfFailRet(getFunction(&iCorFunc));
+ isInstance = !is_static;
return E_ABORT; // Fast exit from cycle.
});
evalStack.front().ResetEntry();
- ULONG32 realArgsCount = Int + (searchStatic ? 0 : 1);
+ ULONG32 realArgsCount = Int + (isInstance ? 1 : 0);
std::vector<ICorDebugValue*> iCorValueArgs;
iCorValueArgs.reserve(realArgsCount);
- if (!searchStatic)
+ if (isInstance)
{
iCorValueArgs.emplace_back(iCorValue.GetPtr());
}
return S_OK;
}
+HRESULT Evaluator::GetMethodClass(ICorDebugThread *pThread, FrameLevel frameLevel, std::string &methodClass, bool &haveThis)
+{
+ HRESULT Status;
+ ToRelease<ICorDebugFrame> pFrame;
+ IfFailRet(GetFrameAt(pThread, frameLevel, &pFrame));
+ if (pFrame == nullptr)
+ return E_FAIL;
+
+ ToRelease<ICorDebugFunction> pFunction;
+ IfFailRet(pFrame->GetFunction(&pFunction));
+
+ ToRelease<ICorDebugModule> pModule;
+ IfFailRet(pFunction->GetModule(&pModule));
+
+ ToRelease<IUnknown> pMDUnknown;
+ IfFailRet(pModule->GetMetaDataInterface(IID_IMetaDataImport, &pMDUnknown));
+ ToRelease<IMetaDataImport> pMD;
+ IfFailRet(pMDUnknown->QueryInterface(IID_IMetaDataImport, (LPVOID*) &pMD));
+
+ mdMethodDef methodDef;
+ IfFailRet(pFunction->GetToken(&methodDef));
+
+ std::string methodName;
+ TypePrinter::GetTypeAndMethod(pFrame, methodClass, methodName);
+
+ DWORD methodAttr = 0;
+ IfFailRet(pMD->GetMethodProps(methodDef, NULL, NULL, 0, NULL, &methodAttr, NULL, NULL, NULL, NULL));
+
+ haveThis = (methodAttr & mdStatic) == 0;
+
+ return S_OK;
+}
+
HRESULT Evaluator::WalkStackVars(ICorDebugThread *pThread, FrameLevel frameLevel, WalkStackVarsCallback cb)
{
HRESULT Status;
FrameLevel frameLevel,
WalkStackVarsCallback cb);
+ HRESULT Evaluator::GetMethodClass(
+ ICorDebugThread *pThread,
+ FrameLevel frameLevel,
+ std::string &methodClass,
+ bool &thisParam);
+
HRESULT GetElement(ICorDebugValue *pInputValue, std::vector<ULONG32> &indexes, ICorDebugValue **ppResultValue);
HRESULT WalkMethods(ICorDebugType *pInputType, WalkMethodsCallback cb);
HRESULT WalkMethods(ICorDebugValue *pInputTypeValue, WalkMethodsCallback cb);
Context.GetAndCheckValue(@"__FILE__:__LINE__", "3", "int", "MITestEvaluate.test_this_t.this_static_i");
// Test method calls.
- Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "Calc1()", "Error");
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", "15", "int", "Calc1()");
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", "15", "int", "test_this_t.Calc1()");
Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "this.Calc1()", "Error");
Context.GetAndCheckValue(@"__FILE__:__LINE__", "16", "int", "Calc2()");
+ Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_this_t.Calc2()", "Error");
Context.GetAndCheckValue(@"__FILE__:__LINE__", "16", "int", "this.Calc2()");
Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"MITestEvaluate.test_this_t\\\"", "string", "ToString()");
Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"MITestEvaluate.test_this_t\\\"", "string", "this.ToString()");
int int_i = 505;
static test_nested test_nested_static_instance;
+ static int stGetInt()
+ {
+ return 111;
+ }
+
+ static int stGetInt(int x)
+ {
+ return x * 2;
+ }
+
+ int getInt()
+ {
+ return 222;
+ }
+
static void Main(string[] args)
{
Label.Checkpoint("init", "values_test", (Object context) => {
Context.EnableBreakpoint(@"__FILE__:__LINE__", "BREAK10");
Context.EnableBreakpoint(@"__FILE__:__LINE__", "BREAK11");
Context.EnableBreakpoint(@"__FILE__:__LINE__", "BREAK12");
+ Context.EnableBreakpoint(@"__FILE__:__LINE__", "BREAK13");
Context.Continue(@"__FILE__:__LINE__");
});
int break_line12 = 1; Label.Breakpoint("BREAK12");
- Label.Checkpoint("unary_operators_test", "finish", (Object context) => {
+ Label.Checkpoint("unary_operators_test", "function_evaluation_test", (Object context) => {
Context Context = (Context)context;
Context.WasBreakpointHit(@"__FILE__:__LINE__", "BREAK12");
Context.Continue(@"__FILE__:__LINE__");
});
+ int break_line_13 = 13; Label.Breakpoint("BREAK13");
+ Label.Checkpoint("function_evaluation_test", "finish", (Object context) => {
+ Context Context = (Context)context;
+ Context.WasBreakpointHit(@"__FILE__:__LINE__", "BREAK13");
+
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", "111", "int", "stGetInt()");
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", "666", "int", "stGetInt(333)");
+ Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "getInt()", "Error:");
+
+ Context.Continue(@"__FILE__:__LINE__");
+ });
+
Label.Checkpoint("finish", "", (Object context) => {
Context Context = (Context)context;
Context.WasExit(@"__FILE__:__LINE__");
Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "3", "int", "VSCodeTestEvaluate.test_this_t.this_static_i");
// Test method calls.
- Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "Calc1()", "error:");
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "15", "int", "Calc1()");
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "15", "int", "test_this_t.Calc1()");
Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "this.Calc1()", "error:");
Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "16", "int", "Calc2()");
Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "16", "int", "this.Calc2()");
+ Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_this_t.Calc2()", "error:");
Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"VSCodeTestEvaluate.test_this_t\"", "string", "ToString()");
Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"VSCodeTestEvaluate.test_this_t\"", "string", "this.ToString()");
Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "Expression has been evaluated and has no value", "void", "TestVoidReturn()");
int int_i = 505;
static test_nested test_nested_static_instance;
+ static int stGetInt()
+ {
+ return 111;
+ }
+
+ static int stGetInt(int x)
+ {
+ return x * 2;
+ }
+
+ int getInt()
+ {
+ return 222;
+ }
+
static void Main(string[] args)
{
Label.Checkpoint("init", "values_test", (Object context) => {
Context.AddBreakpoint(@"__FILE__:__LINE__", "BREAK10");
Context.AddBreakpoint(@"__FILE__:__LINE__", "BREAK11");
Context.AddBreakpoint(@"__FILE__:__LINE__", "BREAK12");
+ Context.AddBreakpoint(@"__FILE__:__LINE__", "BREAK13");
Context.SetBreakpoints(@"__FILE__:__LINE__");
Context.PrepareEnd(@"__FILE__:__LINE__");
Context.WasEntryPointHit(@"__FILE__:__LINE__");
int break_line12 = 1; Label.Breakpoint("BREAK12");
- Label.Checkpoint("unary_operators_test", "finish", (Object context) => {
+ Label.Checkpoint("unary_operators_test", "function_evaluation_test", (Object context) => {
Context Context = (Context)context;
Context.WasBreakpointHit(@"__FILE__:__LINE__", "BREAK12");
Int64 frameId = Context.DetectFrameId(@"__FILE__:__LINE__", "BREAK12");
Context.Continue(@"__FILE__:__LINE__");
});
+ int break_line13 = 13; Label.Breakpoint("BREAK13");
+
+ Label.Checkpoint("function_evaluation_test", "finish", (Object context) => {
+ Context Context = (Context)context;
+ Context.WasBreakpointHit(@"__FILE__:__LINE__", "BREAK13");
+ Int64 frameId = Context.DetectFrameId(@"__FILE__:__LINE__", "BREAK13");
+
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "111", "int", "stGetInt()");
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "222", "int", "stGetInt(111)");
+ Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "getInt()", "error");
+
+ Context.Continue(@"__FILE__:__LINE__");
+ });
+
Label.Checkpoint("finish", "", (Object context) => {
Context Context = (Context)context;
Context.WasExit(@"__FILE__:__LINE__");