From: Mikhail Kurinnoi Date: Fri, 19 Nov 2021 11:13:07 +0000 (-0800) Subject: Fix Set Value by expression feature. X-Git-Tag: submit/tizen/20220215.173642~21 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a3cc9a57e707471866ff07141fcd6b8c94341eb8;p=sdk%2Ftools%2Fnetcoredbg.git Fix Set Value by expression feature. Fix VSCode `setExpression` command and MI/GDB `var-assign` command work with property setter. MI/GDB var-create, var-show-attributes and var-list-children replies will provide "noneditable" attributes in case property don't have setter. --- diff --git a/src/debugger/breakpoints_exception.cpp b/src/debugger/breakpoints_exception.cpp index 4c23c7c..9a838ee 100644 --- a/src/debugger/breakpoints_exception.cpp +++ b/src/debugger/breakpoints_exception.cpp @@ -212,12 +212,12 @@ HRESULT ExceptionBreakpoints::GetExceptionDetails(ICorDebugThread *pThread, ICor HRESULT Status; ToRelease iCorInnerExceptionValue; const bool escape = false; - m_sharedEvaluator->WalkMembers(pExceptionValue, pThread, FrameLevel{0}, [&]( + m_sharedEvaluator->WalkMembers(pExceptionValue, pThread, FrameLevel{0}, false, [&]( ICorDebugType*, bool, const std::string &memberName, Evaluator::GetValueCallback getValue, - Evaluator::SetValueCallback) + Evaluator::SetterData*) { auto getMemberWithName = [&](const std::string &name, std::string &result) -> HRESULT { @@ -491,12 +491,12 @@ HRESULT ExceptionBreakpoints::ManagedCallbackException(ICorDebugThread *pThread, // Note, this is optional field in exception object that could have nulled reference. std::string excMessage; const bool escape = false; - m_sharedEvaluator->WalkMembers(iCorExceptionValue, pThread, FrameLevel{0}, [&]( + m_sharedEvaluator->WalkMembers(iCorExceptionValue, pThread, FrameLevel{0}, false, [&]( ICorDebugType*, bool, const std::string &memberName, Evaluator::GetValueCallback getValue, - Evaluator::SetValueCallback) + Evaluator::SetterData*) { ToRelease pResultValue; diff --git a/src/debugger/evalstackmachine.cpp b/src/debugger/evalstackmachine.cpp index 44678c7..7215aa8 100644 --- a/src/debugger/evalstackmachine.cpp +++ b/src/debugger/evalstackmachine.cpp @@ -8,7 +8,6 @@ #include #include #include "debugger/evalstackmachine.h" -#include "debugger/evaluator.h" #include "debugger/evalhelpers.h" #include "debugger/evalwaiter.h" #include "debugger/valueprint.h" @@ -291,10 +290,17 @@ namespace return S_OK; } - HRESULT GetFrontStackEntryValue(ICorDebugValue **ppResultValue, std::list &evalStack, EvalData &ed, std::string &output) + HRESULT GetFrontStackEntryValue(ICorDebugValue **ppResultValue, std::unique_ptr *resultSetterData, std::list &evalStack, EvalData &ed, std::string &output) { HRESULT Status; - if (FAILED(Status = ed.pEvaluator->ResolveIdentifiers(ed.pThread, ed.frameLevel, evalStack.front().iCorValue, evalStack.front().identifiers, ppResultValue, nullptr, ed.evalFlags)) + Evaluator::SetterData *inputPropertyData = nullptr; + if (evalStack.front().editable) + inputPropertyData = evalStack.front().setterData.get(); + else + resultSetterData = nullptr; + + if (FAILED(Status = ed.pEvaluator->ResolveIdentifiers(ed.pThread, ed.frameLevel, evalStack.front().iCorValue, inputPropertyData, evalStack.front().identifiers, + ppResultValue, resultSetterData, nullptr, ed.evalFlags)) && !evalStack.front().identifiers.empty()) { std::ostringstream ss; @@ -314,7 +320,8 @@ namespace { HRESULT Status; ToRelease iCorValue; - if ((FAILED(Status = ed.pEvaluator->ResolveIdentifiers(ed.pThread, ed.frameLevel, evalStack.front().iCorValue, evalStack.front().identifiers, &iCorValue, ppResultType, ed.evalFlags)) + if ((FAILED(Status = ed.pEvaluator->ResolveIdentifiers(ed.pThread, ed.frameLevel, evalStack.front().iCorValue, nullptr, evalStack.front().identifiers, + &iCorValue, nullptr, ppResultType, ed.evalFlags)) && !evalStack.front().identifiers.empty()) || iCorValue) { std::ostringstream ss; @@ -342,7 +349,7 @@ namespace for (int32_t i = 0; i < dimension; i++) { ToRelease iCorValue; - IfFailRet(GetFrontStackEntryValue(&iCorValue, evalStack, ed, output)); + IfFailRet(GetFrontStackEntryValue(&iCorValue, nullptr, evalStack, ed, output)); evalStack.pop_front(); // TODO implicitly convert iCorValue to int, if type not int @@ -868,14 +875,14 @@ namespace { HRESULT Status; ToRelease iCorValue2; - IfFailRet(GetFrontStackEntryValue(&iCorValue2, evalStack, ed, output)); + IfFailRet(GetFrontStackEntryValue(&iCorValue2, nullptr, evalStack, ed, output)); evalStack.pop_front(); ToRelease iCorRealValue2; CorElementType elemType2; IfFailRet(GetRealValueWithType(iCorValue2, &iCorRealValue2, &elemType2)); ToRelease iCorValue1; - IfFailRet(GetFrontStackEntryValue(&iCorValue1, evalStack, ed, output)); + IfFailRet(GetFrontStackEntryValue(&iCorValue1, nullptr, evalStack, ed, output)); evalStack.front().ResetEntry(); ToRelease iCorRealValue1; CorElementType elemType1; @@ -980,7 +987,7 @@ namespace { HRESULT Status; ToRelease iCorValue; - IfFailRet(GetFrontStackEntryValue(&iCorValue, evalStack, ed, output)); + IfFailRet(GetFrontStackEntryValue(&iCorValue, nullptr, evalStack, ed, output)); evalStack.front().ResetEntry(EvalStackEntry::ResetLiteralStatus::No); ToRelease iCorRealValue; CorElementType elemType; @@ -1067,7 +1074,7 @@ namespace std::vector> iCorArgs(Int); for (int32_t i = Int - 1; i >= 0; i--) { - IfFailRet(GetFrontStackEntryValue(&iCorArgs[i], evalStack, ed, output)); + IfFailRet(GetFrontStackEntryValue(&iCorArgs[i], nullptr, evalStack, ed, output)); evalStack.pop_front(); } @@ -1098,7 +1105,7 @@ namespace ToRelease iCorValue; ToRelease iCorType; - IfFailRet(ed.pEvaluator->ResolveIdentifiers(ed.pThread, ed.frameLevel, evalStack.front().iCorValue, evalStack.front().identifiers, &iCorValue, &iCorType, ed.evalFlags)); + IfFailRet(ed.pEvaluator->ResolveIdentifiers(ed.pThread, ed.frameLevel, evalStack.front().iCorValue, nullptr, evalStack.front().identifiers, &iCorValue, nullptr, &iCorType, ed.evalFlags)); bool searchStatic = false; if (iCorType) @@ -1216,10 +1223,12 @@ namespace return S_OK; ToRelease iCorArrayValue; - IfFailRet(GetFrontStackEntryValue(&iCorArrayValue, evalStack, ed, output)); + std::unique_ptr setterData; + IfFailRet(GetFrontStackEntryValue(&iCorArrayValue, &setterData, evalStack, ed, output)); evalStack.front().iCorValue.Free(); evalStack.front().identifiers.clear(); + evalStack.front().setterData = std::move(setterData); return ed.pEvaluator->GetElement(iCorArrayValue, indexes, &evalStack.front().iCorValue); } @@ -1235,7 +1244,8 @@ namespace return S_OK; ToRelease iCorArrayValue; - IfFailRet(GetFrontStackEntryValue(&iCorArrayValue, evalStack, ed, output)); + std::unique_ptr setterData; + IfFailRet(GetFrontStackEntryValue(&iCorArrayValue, &setterData, evalStack, ed, output)); ToRelease pReferenceValue; IfFailRet(iCorArrayValue->QueryInterface(IID_ICorDebugReferenceValue, (LPVOID*) &pReferenceValue)); @@ -1250,6 +1260,7 @@ namespace evalStack.front().iCorValue.Free(); evalStack.front().identifiers.clear(); + evalStack.front().setterData = std::move(setterData); return ed.pEvaluator->GetElement(iCorArrayValue, indexes, &evalStack.front().iCorValue); } @@ -1353,9 +1364,11 @@ namespace HRESULT Status; ToRelease iCorValue; - IfFailRet(GetFrontStackEntryValue(&iCorValue, evalStack, ed, output)); + std::unique_ptr setterData; + IfFailRet(GetFrontStackEntryValue(&iCorValue, &setterData, evalStack, ed, output)); evalStack.front().iCorValue = iCorValue.Detach(); evalStack.front().identifiers.clear(); + evalStack.front().setterData = std::move(setterData); ToRelease pReferenceValue; IfFailRet(evalStack.front().iCorValue->QueryInterface(IID_ICorDebugReferenceValue, (LPVOID*) &pReferenceValue)); @@ -1646,7 +1659,7 @@ namespace ToRelease iCorRealValueRightOp; ToRelease iCorRightOpValue; CorElementType elemTypeRightOp; - IfFailRet(GetFrontStackEntryValue(&iCorRightOpValue, evalStack, ed, output)); + IfFailRet(GetFrontStackEntryValue(&iCorRightOpValue, nullptr, evalStack, ed, output)); IfFailRet(GetRealValueWithType(iCorRightOpValue, &iCorRealValueRightOp, &elemTypeRightOp)); auto rightOperand = std::move(evalStack.front()); evalStack.pop_front(); @@ -1654,7 +1667,7 @@ namespace ToRelease iCorRealValueLeftOp; ToRelease iCorLeftOpValue; CorElementType elemTypeLeftOp; - IfFailRet(GetFrontStackEntryValue(&iCorLeftOpValue, evalStack, ed, output)); + IfFailRet(GetFrontStackEntryValue(&iCorLeftOpValue, nullptr, evalStack, ed, output)); IfFailRet(GetRealValueWithType(iCorLeftOpValue, &iCorRealValueLeftOp, &elemTypeLeftOp)); std::string typeNameLeft; std::string typeNameRigth; @@ -1698,7 +1711,7 @@ namespace } // unnamed namespace HRESULT EvalStackMachine::Run(ICorDebugThread *pThread, FrameLevel frameLevel, int evalFlags, const std::string &expression, - ICorDebugValue **ppResultValue, bool *editable, std::string &output) + std::list &evalStack, std::string &output) { static const std::vector&, PVOID, std::string&, EvalData&)>> CommandImplementation = { IdentifierName, @@ -1776,38 +1789,50 @@ HRESULT EvalStackMachine::Run(ICorDebugThread *pThread, FrameLevel frameLevel, i { if (FAILED(Status = Interop::NextStackCommand(pStackProgram, Command, pArguments, output)) || Command == ProgramFinished || - FAILED(Status = CommandImplementation[Command](m_evalStack, pArguments, output, m_evalData))) + FAILED(Status = CommandImplementation[Command](evalStack, pArguments, output, m_evalData))) break; } while (1); - do - { - if (FAILED(Status)) - break; + Interop::ReleaseStackMachineProgram(pStackProgram); + return Status; +} - assert(m_evalStack.size() == 1); +HRESULT EvalStackMachine::EvaluateExpression(ICorDebugThread *pThread, FrameLevel frameLevel, int evalFlags, const std::string &expression, ICorDebugValue **ppResultValue, + std::string &output, bool *editable, std::unique_ptr *resultSetterData) +{ + HRESULT Status; + std::list evalStack; + IfFailRet(Run(pThread, frameLevel, evalFlags, expression, evalStack, output)); - if (editable) - *editable = m_evalStack.front().editable; + assert(evalStack.size() == 1); - if (*ppResultValue == nullptr) - { - Status = GetFrontStackEntryValue(ppResultValue, m_evalStack, m_evalData, output); - break; - } + std::unique_ptr setterData; + IfFailRet(GetFrontStackEntryValue(ppResultValue, &setterData, evalStack, m_evalData, output)); - ToRelease iCorValue; - if (FAILED(Status = GetFrontStackEntryValue(&iCorValue, m_evalStack, m_evalData, output))) - break; + if (editable) + *editable = setterData.get() && !setterData.get()->setterFunction ? + false /*property don't have setter*/ : evalStack.front().editable; - Status = ImplicitCast(iCorValue, *ppResultValue, m_evalStack.front().literal, m_evalData); - } - while (0); + if (resultSetterData) + *resultSetterData = std::move(setterData); - Interop::ReleaseStackMachineProgram(pStackProgram); - m_evalStack.clear(); - return Status; + return S_OK; +} + +HRESULT EvalStackMachine::SetValueByExpression(ICorDebugThread *pThread, FrameLevel frameLevel, int evalFlags, ICorDebugValue *pValue, + const std::string &expression, std::string &output) +{ + HRESULT Status; + std::list evalStack; + IfFailRet(Run(pThread, frameLevel, evalFlags, expression, evalStack, output)); + + assert(evalStack.size() == 1); + + ToRelease iCorValue; + IfFailRet(GetFrontStackEntryValue(&iCorValue, nullptr, evalStack, m_evalData, output)); + + return ImplicitCast(iCorValue, pValue, evalStack.front().literal, m_evalData); } HRESULT EvalStackMachine::FindPredefinedTypes(ICorDebugModule *pModule) diff --git a/src/debugger/evalstackmachine.h b/src/debugger/evalstackmachine.h index 0755d77..71d3c44 100644 --- a/src/debugger/evalstackmachine.h +++ b/src/debugger/evalstackmachine.h @@ -14,11 +14,11 @@ #include #include "interfaces/types.h" #include "utils/torelease.h" +#include "debugger/evaluator.h" namespace netcoredbg { -class Evaluator; class EvalHelpers; class EvalWaiter; @@ -44,6 +44,9 @@ struct EvalStackEntry bool literal; // This entry is real variable (not literal, not result of expression calculation, not result of function call, ...). bool editable; + // In case iCorValue is editable and property, we need extra data in order to set value. + // Note, this data directly connected with `iCorValue` and could be available only in case `editable` is true. + std::unique_ptr setterData; EvalStackEntry() : preventBinding(false), literal(false), editable(false) {} @@ -57,6 +60,7 @@ struct EvalStackEntry if (resetLiteral == ResetLiteralStatus::Yes) literal = false; editable = false; + setterData.reset(); } }; @@ -85,9 +89,12 @@ class EvalStackMachine std::shared_ptr m_sharedEvaluator; std::shared_ptr m_sharedEvalHelpers; std::shared_ptr m_sharedEvalWaiter; - std::list m_evalStack; EvalData m_evalData; + // Run stack machine for particular expression. + HRESULT Run(ICorDebugThread *pThread, FrameLevel frameLevel, int evalFlags, const std::string &expression, + std::list &evalStack, std::string &output); + public: void SetupEval(std::shared_ptr &sharedEvaluator, std::shared_ptr &sharedEvalHelpers, std::shared_ptr &sharedEvalWaiter) @@ -100,9 +107,13 @@ public: m_evalData.pEvalWaiter = m_sharedEvalWaiter.get(); } - // Run stack machine for particular expression. - HRESULT Run(ICorDebugThread *pThread, FrameLevel frameLevel, int evalFlags, const std::string &expression, - ICorDebugValue **ppResultValue, bool *editable, std::string &output); + // Evaluate expression. Optional, return `editable` state and in case result is property - setter related information. + HRESULT EvaluateExpression(ICorDebugThread *pThread, FrameLevel frameLevel, int evalFlags, const std::string &expression, ICorDebugValue **ppResultValue, + std::string &output, bool *editable = nullptr, std::unique_ptr *resultSetterData = nullptr); + + // Set value in pValue by expression with implicitly cast expression result to pValue type, if need. + HRESULT SetValueByExpression(ICorDebugThread *pThread, FrameLevel frameLevel, int evalFlags, ICorDebugValue *pValue, + const std::string &expression, std::string &output); // Find ICorDebugClass objects for all predefined types we need for stack machine during Private.CoreLib load. // See ManagedCallback::LoadModule(). diff --git a/src/debugger/evaluator.cpp b/src/debugger/evaluator.cpp index d443330..318c924 100644 --- a/src/debugger/evaluator.cpp +++ b/src/debugger/evaluator.cpp @@ -54,6 +54,7 @@ HRESULT Evaluator::FollowFields(ICorDebugThread *pThread, std::vector &identifiers, int nextIdentifier, ICorDebugValue **ppResult, + std::unique_ptr *resultSetterData, int evalFlags) { HRESULT Status; @@ -71,12 +72,12 @@ HRESULT Evaluator::FollowFields(ICorDebugThread *pThread, ToRelease pClassValue(std::move(pResultValue)); - WalkMembers(pClassValue, pThread, frameLevel, [&]( + WalkMembers(pClassValue, pThread, frameLevel, !!resultSetterData, [&]( ICorDebugType *pType, bool is_static, const std::string &memberName, GetValueCallback getValue, - SetValueCallback) + SetterData *setterData) { if (is_static && valueKind == ValueIsVariable) return S_OK; @@ -87,6 +88,8 @@ HRESULT Evaluator::FollowFields(ICorDebugThread *pThread, return S_OK; IfFailRet(getValue(&pResultValue, evalFlags)); + if (setterData && resultSetterData) + (*resultSetterData).reset(new SetterData(*setterData)); return E_ABORT; // Fast exit from cycle with result. }); @@ -106,6 +109,7 @@ HRESULT Evaluator::FollowNestedFindValue(ICorDebugThread *pThread, const std::string &methodClass, std::vector &identifiers, ICorDebugValue **ppResult, + std::unique_ptr *resultSetterData, int evalFlags) { HRESULT Status; @@ -147,7 +151,7 @@ HRESULT Evaluator::FollowNestedFindValue(ICorDebugThread *pThread, ToRelease pTypeObject; if (S_OK == m_sharedEvalHelpers->CreatTypeObjectStaticConstructor(pThread, pType, &pTypeObject)) { - if (SUCCEEDED(FollowFields(pThread, frameLevel, pTypeObject, ValueIsClass, staticName, 0, ppResult, evalFlags))) + if (SUCCEEDED(FollowFields(pThread, frameLevel, pTypeObject, ValueIsClass, staticName, 0, ppResult, resultSetterData, evalFlags))) return S_OK; } trim = true; @@ -157,7 +161,7 @@ HRESULT Evaluator::FollowNestedFindValue(ICorDebugThread *pThread, ToRelease pTypeObject; IfFailRet(m_sharedEvalHelpers->CreatTypeObjectStaticConstructor(pThread, pType, &pTypeObject)); if (Status == S_OK && // type have static members (S_FALSE if type don't have static members) - SUCCEEDED(FollowFields(pThread, frameLevel, pTypeObject, ValueIsClass, fieldName, 0, ppResult, evalFlags))) + SUCCEEDED(FollowFields(pThread, frameLevel, pTypeObject, ValueIsClass, fieldName, 0, ppResult, resultSetterData, evalFlags))) return S_OK; trim = true; @@ -212,8 +216,10 @@ static HRESULT FollowNestedFindType(ICorDebugThread *pThread, HRESULT Evaluator::ResolveIdentifiers(ICorDebugThread *pThread, FrameLevel frameLevel, ICorDebugValue *pInputValue, + SetterData *inputSetterData, std::vector &identifiers, ICorDebugValue **ppResultValue, + std::unique_ptr *resultSetterData, ICorDebugType **ppResultType, int evalFlags) { @@ -221,11 +227,13 @@ HRESULT Evaluator::ResolveIdentifiers(ICorDebugThread *pThread, { pInputValue->AddRef(); *ppResultValue = pInputValue; + if (inputSetterData && resultSetterData) + (*resultSetterData).reset(new SetterData(*inputSetterData)); return S_OK; } else if (pInputValue) { - return FollowFields(pThread, frameLevel, pInputValue, Evaluator::ValueIsVariable, identifiers, 0, ppResultValue, evalFlags); + return FollowFields(pThread, frameLevel, pInputValue, Evaluator::ValueIsVariable, identifiers, 0, ppResultValue, resultSetterData, evalFlags); } HRESULT Status; @@ -273,7 +281,7 @@ HRESULT Evaluator::ResolveIdentifiers(ICorDebugThread *pThread, if (identifiers[nextIdentifier] == "this") nextIdentifier++; // skip first identifier with "this" (we have it in pThisValue), check rest - if (SUCCEEDED(FollowFields(pThread, frameLevel, pThisValue, ValueIsVariable, identifiers, nextIdentifier, &pResolvedValue, evalFlags))) + if (SUCCEEDED(FollowFields(pThread, frameLevel, pThisValue, ValueIsVariable, identifiers, nextIdentifier, &pResolvedValue, resultSetterData, evalFlags))) { *ppResultValue = pResolvedValue.Detach(); return S_OK; @@ -291,7 +299,7 @@ HRESULT Evaluator::ResolveIdentifiers(ICorDebugThread *pThread, std::string methodName; TypePrinter::GetTypeAndMethod(pFrame, methodClass, methodName); - if (SUCCEEDED(FollowNestedFindValue(pThread, frameLevel, methodClass, identifiers, &pResolvedValue, evalFlags))) + if (SUCCEEDED(FollowNestedFindValue(pThread, frameLevel, methodClass, identifiers, &pResolvedValue, resultSetterData, evalFlags))) { *ppResultValue = pResolvedValue.Detach(); return S_OK; @@ -335,7 +343,7 @@ HRESULT Evaluator::ResolveIdentifiers(ICorDebugThread *pThread, } ToRelease pValue(std::move(pResolvedValue)); - IfFailRet(FollowFields(pThread, frameLevel, pValue, valueKind, identifiers, nextIdentifier, &pResolvedValue, evalFlags)); + IfFailRet(FollowFields(pThread, frameLevel, pValue, valueKind, identifiers, nextIdentifier, &pResolvedValue, resultSetterData, evalFlags)); *ppResultValue = pResolvedValue.Detach(); return S_OK; @@ -606,11 +614,56 @@ HRESULT Evaluator::WalkMethods(ICorDebugType *pInputType, WalkMethodsCallback cb return S_OK; } +HRESULT Evaluator::SetValue(ICorDebugThread *pThread, FrameLevel frameLevel, ICorDebugValue *pValue, SetterData *setterData, + const std::string &value, int evalFlags, std::string &output) +{ + if (!pThread) + return E_FAIL; + + // In case this is not property, just change value itself. + if (!setterData) + return m_sharedEvalStackMachine->SetValueByExpression(pThread, frameLevel, evalFlags, pValue, value, output); + + HRESULT Status; + pValue->AddRef(); + ToRelease iCorValue(pValue); + CorElementType corType; + IfFailRet(iCorValue->GetType(&corType)); + + if (corType == ELEMENT_TYPE_STRING) + { + // FIXME investigate, why in this case we can't use ICorDebugReferenceValue::SetValue() for string in iCorValue + iCorValue.Free(); + IfFailRet(m_sharedEvalStackMachine->EvaluateExpression(pThread, frameLevel, evalFlags, value, &iCorValue, output)); + + CorElementType elemType; + IfFailRet(iCorValue->GetType(&elemType)); + if (elemType != ELEMENT_TYPE_STRING) + return E_INVALIDARG; + } + else // Allow stack machine decide what types are supported. + { + IfFailRet(m_sharedEvalStackMachine->SetValueByExpression(pThread, frameLevel, evalFlags, iCorValue.GetPtr(), value, output)); + } + + // Call setter. + if (!setterData->thisValue) + { + return m_sharedEvalHelpers->EvalFunction(pThread, setterData->setterFunction, nullptr, 0, iCorValue.GetRef(), 1, nullptr, evalFlags); + } + else + { + ICorDebugValue *ppArgsValue[] = {setterData->thisValue, iCorValue}; + return m_sharedEvalHelpers->EvalFunction(pThread, setterData->setterFunction, nullptr, 0, ppArgsValue, 2, nullptr, evalFlags); + } +} + HRESULT Evaluator::WalkMembers( ICorDebugValue *pInputValue, ICorDebugThread *pThread, FrameLevel frameLevel, ICorDebugType *pTypeCast, + bool provideSetterData, WalkMembersCallback cb) { HRESULT Status = S_OK; @@ -634,17 +687,7 @@ HRESULT Evaluator::WalkMembers( return S_OK; }; - auto setValue = [&](const std::string &value, std::string &output, int evalFlags) -> HRESULT - { - if (!pThread) - return E_FAIL; - - ToRelease iCorValue; - IfFailRet(getValue(&iCorValue, evalFlags)); - return m_sharedEvalStackMachine->Run(pThread, frameLevel, evalFlags, value, iCorValue.GetRef(), nullptr, output); - }; - - return cb(nullptr, false, "", getValue, setValue); + return cb(nullptr, false, "", getValue, nullptr); } ToRelease pArrayValue; @@ -674,17 +717,7 @@ HRESULT Evaluator::WalkMembers( return S_OK; }; - auto setValue = [&](const std::string &value, std::string &output, int evalFlags) -> HRESULT - { - if (!pThread) - return E_FAIL; - - ToRelease iCorValue; - IfFailRet(getValue(&iCorValue, evalFlags)); - return m_sharedEvalStackMachine->Run(pThread, frameLevel, evalFlags, value, iCorValue.GetRef(), nullptr, output); - }; - - IfFailRet(cb(nullptr, false, "[" + IndiciesToStr(ind, base) + "]", getValue, setValue)); + IfFailRet(cb(nullptr, false, "[" + IndiciesToStr(ind, base) + "]", getValue, nullptr)); IncIndicies(ind, dims); } @@ -783,17 +816,7 @@ HRESULT Evaluator::WalkMembers( return S_OK; }; - auto setValue = [&](const std::string &value, std::string &output, int evalFlags) -> HRESULT - { - if (!pThread) - return E_FAIL; - - ToRelease iCorValue; - IfFailRet(getValue(&iCorValue, evalFlags)); - return m_sharedEvalStackMachine->Run(pThread, frameLevel, evalFlags, value, iCorValue.GetRef(), nullptr, output); - }; - - IfFailRet(cb(pType, is_static, name, getValue, setValue)); + IfFailRet(cb(pType, is_static, name, getValue, nullptr)); } return S_OK; })); @@ -879,47 +902,20 @@ HRESULT Evaluator::WalkMembers( return m_sharedEvalHelpers->EvalFunction(pThread, iCorFunc, pType.GetRef(), 1, is_static ? nullptr : &pInputValue, is_static ? 0 : 1, ppResultValue, evalFlags); }; - auto setValue = [&](const std::string &value, std::string &output, int evalFlags) -> HRESULT + if (provideSetterData) { - if (!pThread) - return E_FAIL; - - ToRelease iCorFunc; - IfFailRet(pModule->GetFunctionFromToken(mdSetter, &iCorFunc)); - - ToRelease iCorValue; - IfFailRet(getValue(&iCorValue, evalFlags)); - CorElementType corType; - IfFailRet(iCorValue->GetType(&corType)); - - if (corType == ELEMENT_TYPE_STRING) - { - // FIXME investigate, why in this case we can't use ICorDebugReferenceValue::SetValue() for string in iCorValue - iCorValue.Free(); - IfFailRet(m_sharedEvalStackMachine->Run(pThread, frameLevel, evalFlags, value, &iCorValue, nullptr, output)); - - CorElementType elemType; - IfFailRet(iCorValue->GetType(&elemType)); - if (elemType != ELEMENT_TYPE_STRING) - return E_INVALIDARG; - } - else // Allow stack machine decide what types are supported. - { - IfFailRet(m_sharedEvalStackMachine->Run(pThread, frameLevel, evalFlags, value, iCorValue.GetRef(), nullptr, output)); - } - - // Call setter. - if (is_static) - { - return m_sharedEvalHelpers->EvalFunction(pThread, iCorFunc, nullptr, 0, iCorValue.GetRef(), 1, nullptr, evalFlags); - } - else + ToRelease iCorFuncSetter; + if (FAILED(pModule->GetFunctionFromToken(mdSetter, &iCorFuncSetter))) { - ICorDebugValue *ppArgsValue[] = {pInputValue, iCorValue}; - return m_sharedEvalHelpers->EvalFunction(pThread, iCorFunc, nullptr, 0, ppArgsValue, 2, nullptr, evalFlags); + iCorFuncSetter.Free(); } - }; - IfFailRet(cb(pType, is_static, name, getValue, setValue)); + SetterData setterData(is_static ? nullptr : pInputValue, iCorFuncSetter); + IfFailRet(cb(pType, is_static, name, getValue, &setterData)); + } + else + { + IfFailRet(cb(pType, is_static, name, getValue, nullptr)); + } } return S_OK; })); @@ -938,7 +934,7 @@ HRESULT Evaluator::WalkMembers( IfFailRet(m_sharedEvalHelpers->CreatTypeObjectStaticConstructor(pThread, pBaseType)); } // Add fields of base class - IfFailRet(WalkMembers(pInputValue, pThread, frameLevel, pBaseType, cb)); + IfFailRet(WalkMembers(pInputValue, pThread, frameLevel, pBaseType, provideSetterData, cb)); } } @@ -949,9 +945,10 @@ HRESULT Evaluator::WalkMembers( ICorDebugValue *pValue, ICorDebugThread *pThread, FrameLevel frameLevel, + bool provideSetterData, WalkMembersCallback cb) { - return WalkMembers(pValue, pThread, frameLevel, nullptr, cb); + return WalkMembers(pValue, pThread, frameLevel, nullptr, provideSetterData, cb); } static bool has_prefix(const std::string &s, const std::string &prefix) @@ -975,12 +972,12 @@ static HRESULT HandleSpecialLocalVar( return S_FALSE; // Substitute local value with its fields - IfFailRet(pEvaluator->WalkMembers(pLocalValue, nullptr, FrameLevel{0}, [&]( + IfFailRet(pEvaluator->WalkMembers(pLocalValue, nullptr, FrameLevel{0}, false, [&]( ICorDebugType *, bool is_static, const std::string &name, Evaluator::GetValueCallback getValue, - Evaluator::SetValueCallback) + Evaluator::SetterData*) { if (is_static) return S_OK; @@ -1020,12 +1017,12 @@ static HRESULT HandleSpecialThisParam( return S_FALSE; // Substitute this with its fields - IfFailRet(pEvaluator->WalkMembers(pThisValue, nullptr, FrameLevel{0}, [&]( + IfFailRet(pEvaluator->WalkMembers(pThisValue, nullptr, FrameLevel{0}, false, [&]( ICorDebugType *, bool is_static, const std::string &name, Evaluator::GetValueCallback getValue, - Evaluator::SetValueCallback) + Evaluator::SetterData*) { HRESULT Status; if (is_static) diff --git a/src/debugger/evaluator.h b/src/debugger/evaluator.h index ed79e9b..77e37e8 100644 --- a/src/debugger/evaluator.h +++ b/src/debugger/evaluator.h @@ -37,9 +37,35 @@ public: }; typedef ArgElementType ReturnElementType; + struct SetterData + { + ToRelease thisValue; + ToRelease setterFunction; + + SetterData(ICorDebugValue *pValue, ICorDebugFunction *pFunction) + { + Set(pValue, pFunction); + }; + + SetterData(SetterData &setterData) + { + Set(setterData.thisValue.GetPtr(), setterData.setterFunction.GetPtr()); + }; + + void Set(ICorDebugValue *pValue, ICorDebugFunction *pFunction) + { + if (pValue) + pValue->AddRef(); + thisValue = pValue; + + if (pFunction) + pFunction->AddRef(); + setterFunction = pFunction; + } + }; + typedef std::function GetValueCallback; - typedef std::function SetValueCallback; - typedef std::function WalkMembersCallback; + typedef std::function WalkMembersCallback; typedef std::function WalkStackVarsCallback; typedef std::function GetFunctionCallback; typedef std::function&,GetFunctionCallback)> WalkMethodsCallback; @@ -63,8 +89,10 @@ public: ICorDebugThread *pThread, FrameLevel frameLevel, ICorDebugValue *pInputValue, + SetterData *inputSetterData, std::vector &identifiers, ICorDebugValue **ppResultValue, + std::unique_ptr *resultSetterData, ICorDebugType **ppResultType, int evalFlags); @@ -72,6 +100,7 @@ public: ICorDebugValue *pValue, ICorDebugThread *pThread, FrameLevel frameLevel, + bool provideSetterData, WalkMembersCallback cb); HRESULT WalkStackVars( @@ -89,6 +118,9 @@ public: HRESULT WalkMethods(ICorDebugType *pInputType, WalkMethodsCallback cb); HRESULT WalkMethods(ICorDebugValue *pInputTypeValue, WalkMethodsCallback cb); + HRESULT SetValue(ICorDebugThread *pThread, FrameLevel frameLevel, ICorDebugValue *pValue, SetterData *setterData, + const std::string &value, int evalFlags, std::string &output); + private: std::shared_ptr m_sharedModules; @@ -101,6 +133,7 @@ private: const std::string &methodClass, std::vector &identifiers, ICorDebugValue **ppResult, + std::unique_ptr *resultSetterData, int evalFlags); HRESULT FollowFields( @@ -111,6 +144,7 @@ private: std::vector &identifiers, int nextIdentifier, ICorDebugValue **ppResult, + std::unique_ptr *resultSetterData, int evalFlags); HRESULT WalkMembers( @@ -118,6 +152,7 @@ private: ICorDebugThread *pThread, FrameLevel frameLevel, ICorDebugType *pTypeCast, + bool provideSetterData, WalkMembersCallback cb); }; diff --git a/src/debugger/manageddebugger.cpp b/src/debugger/manageddebugger.cpp index 8e996c3..ab1216a 100644 --- a/src/debugger/manageddebugger.cpp +++ b/src/debugger/manageddebugger.cpp @@ -997,23 +997,16 @@ HRESULT ManagedDebugger::Evaluate(FrameId frameId, const std::string &expression HRESULT ManagedDebugger::SetVariable(const std::string &name, const std::string &value, uint32_t ref, std::string &output) { + LogFuncEntry(); + return m_sharedVariables->SetVariable(m_iCorProcess, name, value, ref, output); } -HRESULT ManagedDebugger::SetVariableByExpression( - FrameId frameId, - const std::string &evaluateName, - int evalFlags, - const std::string &value, - std::string &output) +HRESULT ManagedDebugger::SetExpression(FrameId frameId, const std::string &expression, int evalFlags, const std::string &value, std::string &output) { LogFuncEntry(); - HRESULT Status; - ToRelease pResultValue; - - IfFailRet(m_sharedVariables->GetValueByExpression(m_iCorProcess, frameId, evaluateName, evalFlags, &pResultValue)); - return m_sharedVariables->SetVariable(m_iCorProcess, pResultValue, value, frameId, evalFlags, output); + return m_sharedVariables->SetExpression(m_iCorProcess, frameId, expression, evalFlags, value, output); } diff --git a/src/debugger/manageddebugger.h b/src/debugger/manageddebugger.h index e283dfa..73d8d47 100644 --- a/src/debugger/manageddebugger.h +++ b/src/debugger/manageddebugger.h @@ -155,7 +155,7 @@ public: int GetNamedVariables(uint32_t variablesReference) override; HRESULT Evaluate(FrameId frameId, const std::string &expression, Variable &variable, std::string &output) override; HRESULT SetVariable(const std::string &name, const std::string &value, uint32_t ref, std::string &output) override; - HRESULT SetVariableByExpression(FrameId frameId, const std::string &evaluateName, int evalFlags, const std::string &value, std::string &output) override; + HRESULT SetExpression(FrameId frameId, const std::string &expression, int evalFlags, const std::string &value, std::string &output) override; HRESULT GetExceptionInfo(ThreadId threadId, ExceptionInfo &exceptionInfo) override; HRESULT GetSourceFile(const std::string &sourcePath, char** fileBuf, int* fileLen) override; void FreeUnmanaged(PVOID mem) override; diff --git a/src/debugger/variables.cpp b/src/debugger/variables.cpp index 885a37c..ffb1dcd 100644 --- a/src/debugger/variables.cpp +++ b/src/debugger/variables.cpp @@ -37,12 +37,12 @@ void Variables::GetNumChild( int numStatic = 0; int numInstance = 0; // No thread and FrameLevel{0} here, since we need only count childs. - if (FAILED(m_sharedEvaluator->WalkMembers(pValue, nullptr, FrameLevel{0}, [&numStatic, &numInstance]( + if (FAILED(m_sharedEvaluator->WalkMembers(pValue, nullptr, FrameLevel{0}, false, [&numStatic, &numInstance]( ICorDebugType *, bool is_static, const std::string &, Evaluator::GetValueCallback, - Evaluator::SetValueCallback) + Evaluator::SetterData*) { if (is_static) numStatic++; @@ -109,12 +109,12 @@ HRESULT Variables::FetchFieldsAndProperties( int currentIndex = -1; - IfFailRet(m_sharedEvaluator->WalkMembers(pInputValue, pThread, frameLevel, [&]( + IfFailRet(m_sharedEvaluator->WalkMembers(pInputValue, pThread, frameLevel, false, [&]( ICorDebugType *pType, bool is_static, const std::string &name, Evaluator::GetValueCallback getValue, - Evaluator::SetValueCallback) + Evaluator::SetterData*) { if (is_static) hasStaticMembers = true; @@ -418,7 +418,7 @@ HRESULT Variables::Evaluate( ToRelease pResultValue; FrameLevel frameLevel = frameId.getLevel(); - IfFailRet(m_sharedEvalStackMachine->Run(pThread, frameLevel, variable.evalFlags, expression, &pResultValue, &variable.editable, output)); + IfFailRet(m_sharedEvalStackMachine->EvaluateExpression(pThread, frameLevel, variable.evalFlags, expression, &pResultValue, output, &variable.editable)); variable.evaluateName = expression; IfFailRet(PrintValue(pResultValue, variable.value)); @@ -477,7 +477,7 @@ HRESULT Variables::SetStackVariable( ToRelease iCorValue; IfFailRet(getValue(&iCorValue, ref.evalFlags)); - IfFailRet(m_sharedEvalStackMachine->Run(pThread, ref.frameId.getLevel(), ref.evalFlags, value, iCorValue.GetRef(), nullptr, output)); + IfFailRet(m_sharedEvaluator->SetValue(pThread, ref.frameId.getLevel(), iCorValue, nullptr, value, ref.evalFlags, output)); IfFailRet(PrintValue(iCorValue, output)); return E_ABORT; // Fast exit from cycle. })) && Status != E_ABORT) @@ -503,58 +503,35 @@ HRESULT Variables::SetChild( HRESULT Status; - IfFailRet(m_sharedEvaluator->WalkMembers(ref.iCorValue, pThread, ref.frameId.getLevel(), [&]( + if (FAILED(Status = m_sharedEvaluator->WalkMembers(ref.iCorValue, pThread, ref.frameId.getLevel(), true, [&]( ICorDebugType*, bool is_static, const std::string &varName, Evaluator::GetValueCallback getValue, - Evaluator::SetValueCallback setValue) -> HRESULT + Evaluator::SetterData *setterData) -> HRESULT { - if (varName == name) - { - IfFailRet(setValue(value, output, ref.evalFlags)); - ToRelease iCorValue; - IfFailRet(getValue(&iCorValue, ref.evalFlags)); - IfFailRet(PrintValue(iCorValue, output)); - } - return S_OK; - })); - - return S_OK; -} - -HRESULT Variables::GetValueByExpression(ICorDebugProcess *pProcess, FrameId frameId, - const std::string &evaluateName, int evalFlags, ICorDebugValue **ppResult) -{ - if (pProcess == nullptr) - return E_FAIL; - - HRESULT Status; - - ThreadId threadId = frameId.getThread(); - if (!threadId) - return E_FAIL; + if (varName != name) + return S_OK; - ToRelease pThread; - IfFailRet(pProcess->GetThread(int(threadId), &pThread)); + if (setterData && !setterData->setterFunction) + return E_FAIL; - // Looks like all we need here is get ICorDebugValue by field/variable name. - // All "set value" code must be refactored in order to remove dependency from Roslyn. + ToRelease iCorValue; + IfFailRet(getValue(&iCorValue, ref.evalFlags)); + IfFailRet(m_sharedEvaluator->SetValue(pThread, ref.frameId.getLevel(), iCorValue, setterData, value, ref.evalFlags, output)); + IfFailRet(PrintValue(iCorValue, output)); + return E_ABORT; // Fast exit from cycle. + })) && Status != E_ABORT) + { + return Status; + } - std::string output; - return m_sharedEvalStackMachine->Run(pThread, frameId.getLevel(), evalFlags, evaluateName, ppResult, nullptr, output); + return S_OK; } -HRESULT Variables::SetVariable( - ICorDebugProcess *pProcess, - ICorDebugValue *pVariable, - const std::string &value, - FrameId frameId, - int evalFlags, - std::string &output) +HRESULT Variables::SetExpression(ICorDebugProcess *pProcess, FrameId frameId, const std::string &expression, + int evalFlags, const std::string &value, std::string &output) { - HRESULT Status; - if (pProcess == nullptr) return E_FAIL; @@ -562,11 +539,23 @@ HRESULT Variables::SetVariable( if (!threadId) return E_FAIL; + HRESULT Status; ToRelease pThread; IfFailRet(pProcess->GetThread(int(threadId), &pThread)); - IfFailRet(m_sharedEvalStackMachine->Run(pThread, frameId.getLevel(), evalFlags, value, &pVariable, nullptr, output)); - IfFailRet(PrintValue(pVariable, output)); + ToRelease iCorValue; + bool editable = false; + std::unique_ptr setterData; + IfFailRet(m_sharedEvalStackMachine->EvaluateExpression(pThread, frameId.getLevel(), evalFlags, expression, &iCorValue, output, &editable, &setterData)); + if (!editable || + (editable && setterData.get() && !setterData.get()->setterFunction)) // property, that don't have setter + { + output = "'" + expression + "' cannot be assigned to"; + return E_INVALIDARG; + } + + IfFailRet(m_sharedEvaluator->SetValue(pThread, frameId.getLevel(), iCorValue, setterData.get(), value, evalFlags, output)); + IfFailRet(PrintValue(iCorValue, output)); return S_OK; } diff --git a/src/debugger/variables.h b/src/debugger/variables.h index e4aa977..9f05013 100644 --- a/src/debugger/variables.h +++ b/src/debugger/variables.h @@ -153,12 +153,12 @@ public: uint32_t ref, std::string &output); - HRESULT SetVariable( + HRESULT SetExpression( ICorDebugProcess *pProcess, - ICorDebugValue *pVariable, - const std::string &value, FrameId frameId, + const std::string &expression, int evalFlags, + const std::string &value, std::string &output); HRESULT GetScopes( @@ -173,13 +173,6 @@ public: Variable &variable, std::string &output); - HRESULT GetValueByExpression( - ICorDebugProcess *pProcess, - FrameId frameId, - const std::string &evaluateName, - int evalFlags, - ICorDebugValue **ppResult); - HRESULT GetExceptionVariable( FrameId frameId, ICorDebugThread *pThread, diff --git a/src/interfaces/idebugger.h b/src/interfaces/idebugger.h index ae23368..f3885e1 100644 --- a/src/interfaces/idebugger.h +++ b/src/interfaces/idebugger.h @@ -96,7 +96,7 @@ public: virtual int GetNamedVariables(uint32_t variablesReference) = 0; virtual HRESULT Evaluate(FrameId frameId, const std::string &expression, Variable &variable, std::string &output) = 0; virtual HRESULT SetVariable(const std::string &name, const std::string &value, uint32_t ref, std::string &output) = 0; - virtual HRESULT SetVariableByExpression(FrameId frameId, const std::string &evaluateName, int evalFlags, const std::string &value, std::string &output) = 0; + virtual HRESULT SetExpression(FrameId frameId, const std::string &expression, int evalFlags, const std::string &value, std::string &output) = 0; virtual HRESULT GetExceptionInfo(ThreadId threadId, ExceptionInfo &exceptionInfo) = 0; virtual HRESULT GetSourceFile(const std::string &sourcePath, char** fileBuf, int* fileLen) = 0; virtual void FreeUnmanaged(PVOID mem) = 0; diff --git a/src/protocols/miprotocol.cpp b/src/protocols/miprotocol.cpp index b8dd1c6..b75a79d 100644 --- a/src/protocols/miprotocol.cpp +++ b/src/protocols/miprotocol.cpp @@ -1066,7 +1066,7 @@ HRESULT MIProtocol::HandleCommand(const std::string& command, const std::vector< IfFailRet(FindVar(varName, miVariable)); FrameId frameId(miVariable.threadId, miVariable.level); - IfFailRet(m_sharedDebugger->SetVariableByExpression(frameId, miVariable.variable.evaluateName, miVariable.variable.evalFlags, varExpr, output)); + IfFailRet(m_sharedDebugger->SetExpression(frameId, miVariable.variable.evaluateName, miVariable.variable.evalFlags, varExpr, output)); output = "value=\"" + MIProtocol::EscapeMIValue(output) + "\""; diff --git a/src/protocols/vscodeprotocol.cpp b/src/protocols/vscodeprotocol.cpp index 47194db..692978d 100644 --- a/src/protocols/vscodeprotocol.cpp +++ b/src/protocols/vscodeprotocol.cpp @@ -722,7 +722,7 @@ HRESULT VSCodeProtocol::HandleCommand(const std::string &command, const json &ar // VSCode don't support evaluation flags, we can't disable implicit function calls during evaluation. // https://github.com/OmniSharp/omnisharp-vscode/issues/3173 std::string output; - Status = m_sharedDebugger->SetVariableByExpression(frameId, expression, defaultEvalFlags, value, output); + Status = m_sharedDebugger->SetExpression(frameId, expression, defaultEvalFlags, value, output); if (FAILED(Status)) { if (output.empty()) diff --git a/test-suite/MITestVariables/Program.cs b/test-suite/MITestVariables/Program.cs index 79cf3c9..124632c 100644 --- a/test-suite/MITestVariables/Program.cs +++ b/test-suite/MITestVariables/Program.cs @@ -1037,23 +1037,25 @@ namespace MITestVariables Context.CreateAndCompareVar(@"__FILE__:__LINE__", "setVarStruct.prop_i", "2002"); Context.CreateAndCompareVar(@"__FILE__:__LINE__", "setVarStruct.prop_i_noset", "5002"); Context.CreateAndAssignVar(@"__FILE__:__LINE__", "TestSetVarStruct.static_field_i", "3001"); - // FIXME debugger must be fixed first //Context.CreateAndAssignVar(@"__FILE__:__LINE__", "TestSetVarStruct.static_prop_i", "3002"); - // FIXME debugger must be fixed first //Context.ErrorAtAssignVar(@"__FILE__:__LINE__", "TestSetVarStruct.static_prop_i_noset", "3003"); + Context.CreateAndAssignVar(@"__FILE__:__LINE__", "TestSetVarStruct.static_prop_i", "3002"); + Context.ErrorAtAssignVar(@"__FILE__:__LINE__", "TestSetVarStruct.static_prop_i_noset", "3003"); Context.CreateAndAssignVar(@"__FILE__:__LINE__", "setVarStruct.field_i", "4001"); - // FIXME debugger must be fixed first //Context.CreateAndAssignVar(@"__FILE__:__LINE__", "setVarStruct.prop_i", "4002"); - // FIXME debugger must be fixed first //Context.ErrorAtAssignVar(@"__FILE__:__LINE__", "setVarStruct.prop_i_noset", "4003"); + Context.CreateAndAssignVar(@"__FILE__:__LINE__", "setVarStruct.prop_i", "4002"); + Context.ErrorAtAssignVar(@"__FILE__:__LINE__", "setVarStruct.prop_i_noset", "4003"); Context.CreateAndCompareVar(@"__FILE__:__LINE__", "TestSetVarStruct.static_field_i", "3001"); - // FIXME debugger must be fixed first //Context.CreateAndCompareVar(@"__FILE__:__LINE__", "TestSetVarStruct.static_prop_i", "3002"); + Context.CreateAndCompareVar(@"__FILE__:__LINE__", "TestSetVarStruct.static_prop_i", "3002"); Context.CreateAndCompareVar(@"__FILE__:__LINE__", "setVarStruct.field_i", "4001"); - // FIXME debugger must be fixed first //Context.CreateAndCompareVar(@"__FILE__:__LINE__", "setVarStruct.prop_i", "4002"); - // FIXME debugger must be fixed first //Context.ErrorAtAssignVar(@"__FILE__:__LINE__", "1+1", "2"); - // FIXME debugger must be fixed first //Context.ErrorAtAssignVar(@"__FILE__:__LINE__", "1", "1"); + Context.CreateAndCompareVar(@"__FILE__:__LINE__", "setVarStruct.prop_i", "4002"); + Context.ErrorAtAssignVar(@"__FILE__:__LINE__", "1+1", "2"); + Context.ErrorAtAssignVar(@"__FILE__:__LINE__", "1", "1"); Context.ErrorAtAssignVar(@"__FILE__:__LINE__", "1.ToString()", "\"1\""); Context.CheckAttributes(@"__FILE__:__LINE__", "array1[0]", "editable"); Context.CheckAttributes(@"__FILE__:__LINE__", "array1?[0]", "editable"); Context.CheckAttributes(@"__FILE__:__LINE__", "litClass.data", "editable"); Context.CheckAttributes(@"__FILE__:__LINE__", "litClass?.data", "editable"); + Context.CheckAttributes(@"__FILE__:__LINE__", "TestSetVarStruct.static_prop_i", "editable"); + Context.CheckAttributes(@"__FILE__:__LINE__", "TestSetVarStruct.static_prop_i_noset", "noneditable"); Context.CheckAttributes(@"__FILE__:__LINE__", "1", "noneditable"); Context.CheckAttributes(@"__FILE__:__LINE__", "-1", "noneditable"); Context.CheckAttributes(@"__FILE__:__LINE__", "-array1[0]", "noneditable"); @@ -1124,9 +1126,9 @@ namespace MITestVariables Context.CreateAndCompareVar(@"__FILE__:__LINE__", "array1[4]", "5"); Context.CreateAndCompareVar(@"__FILE__:__LINE__", "TestSetVarStruct.static_field_i", "3001"); - // FIXME debugger must be fixed first //Context.CreateAndCompareVar(@"__FILE__:__LINE__", "TestSetVarStruct.static_prop_i", "3002"); + Context.CreateAndCompareVar(@"__FILE__:__LINE__", "TestSetVarStruct.static_prop_i", "3002"); Context.CreateAndCompareVar(@"__FILE__:__LINE__", "setVarStruct.field_i", "4001"); - // FIXME debugger must be fixed first //Context.CreateAndCompareVar(@"__FILE__:__LINE__", "setVarStruct.prop_i", "4002"); + Context.CreateAndCompareVar(@"__FILE__:__LINE__", "setVarStruct.prop_i", "4002"); Context.Continue(@"__FILE__:__LINE__"); }); diff --git a/test-suite/VSCodeTestVariables/Program.cs b/test-suite/VSCodeTestVariables/Program.cs index e4ee086..7022048 100644 --- a/test-suite/VSCodeTestVariables/Program.cs +++ b/test-suite/VSCodeTestVariables/Program.cs @@ -1157,16 +1157,16 @@ namespace VSCodeTestVariables Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "setExprStruct.prop_i_noset", "5002"); Context.SetExpression(@"__FILE__:__LINE__", frameId, "TestSetExprStruct.static_field_i", "3001"); Context.SetExpression(@"__FILE__:__LINE__", frameId, "TestSetExprStruct.static_prop_i", "3002"); - // FIXME debugger must be fixed first //Context.ErrorSetExpression(@"__FILE__:__LINE__", frameId, "TestSetExprStruct.static_prop_i_noset", "3003"); + Context.ErrorSetExpression(@"__FILE__:__LINE__", frameId, "TestSetExprStruct.static_prop_i_noset", "3003"); Context.SetExpression(@"__FILE__:__LINE__", frameId, "setExprStruct.field_i", "4001"); Context.SetExpression(@"__FILE__:__LINE__", frameId, "setExprStruct.prop_i", "4002"); - // FIXME debugger must be fixed first //Context.ErrorSetExpression(@"__FILE__:__LINE__", frameId, "setExprStruct.prop_i_noset", "4003"); + Context.ErrorSetExpression(@"__FILE__:__LINE__", frameId, "setExprStruct.prop_i_noset", "4003"); Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "TestSetExprStruct.static_field_i", "3001"); - // FIXME debugger must be fixed first //Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "TestSetExprStruct.static_prop_i", "3002"); + Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "TestSetExprStruct.static_prop_i", "3002"); Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "setExprStruct.field_i", "4001"); - // FIXME debugger must be fixed first //Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "setExprStruct.prop_i", "4002"); - // FIXME debugger must be fixed first //Context.ErrorSetExpression(@"__FILE__:__LINE__", frameId, "1+1", "2"); - // FIXME debugger must be fixed first //Context.ErrorSetExpression(@"__FILE__:__LINE__", frameId, "1", "1"); + Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "setExprStruct.prop_i", "4002"); + Context.ErrorSetExpression(@"__FILE__:__LINE__", frameId, "1+1", "2"); + Context.ErrorSetExpression(@"__FILE__:__LINE__", frameId, "1", "1"); Context.ErrorSetExpression(@"__FILE__:__LINE__", frameId, "1.ToString()", "\"1\""); Context.Continue(@"__FILE__:__LINE__"); @@ -1240,9 +1240,9 @@ namespace VSCodeTestVariables Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "setVarStruct.prop_i", "4002"); Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "TestSetExprStruct.static_field_i", "3001"); - // FIXME debugger must be fixed first //Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "TestSetExprStruct.static_prop_i", "3002"); + Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "TestSetExprStruct.static_prop_i", "3002"); Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "setExprStruct.field_i", "4001"); - // FIXME debugger must be fixed first //Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "setExprStruct.prop_i", "4002"); + Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "setExprStruct.prop_i", "4002"); Context.Continue(@"__FILE__:__LINE__"); });