Fix Set Value by expression feature.
authorMikhail Kurinnoi <m.kurinnoi@samsung.com>
Fri, 19 Nov 2021 11:13:07 +0000 (03:13 -0800)
committerAlexander Soldatov/Platform Lab /SRR/Staff Engineer/Samsung Electronics <soldatov.a@samsung.com>
Thu, 2 Dec 2021 16:58:54 +0000 (19:58 +0300)
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.

14 files changed:
src/debugger/breakpoints_exception.cpp
src/debugger/evalstackmachine.cpp
src/debugger/evalstackmachine.h
src/debugger/evaluator.cpp
src/debugger/evaluator.h
src/debugger/manageddebugger.cpp
src/debugger/manageddebugger.h
src/debugger/variables.cpp
src/debugger/variables.h
src/interfaces/idebugger.h
src/protocols/miprotocol.cpp
src/protocols/vscodeprotocol.cpp
test-suite/MITestVariables/Program.cs
test-suite/VSCodeTestVariables/Program.cs

index 4c23c7ceb852234d3af59c13a331eb37e3f50517..9a838ee9f536bdd31bbc4f38fd2abd2906077405 100644 (file)
@@ -212,12 +212,12 @@ HRESULT ExceptionBreakpoints::GetExceptionDetails(ICorDebugThread *pThread, ICor
     HRESULT Status;
     ToRelease<ICorDebugValue> 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<ICorDebugValue> pResultValue;
 
index 44678c71c631b99bac930b575c4af946c57afebe..7215aa8ecb236b73fa756bdafad502dbf5c927d5 100644 (file)
@@ -8,7 +8,6 @@
 #include <iterator>
 #include <arrayholder.h>
 #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<EvalStackEntry> &evalStack, EvalData &ed, std::string &output)
+    HRESULT GetFrontStackEntryValue(ICorDebugValue **ppResultValue, std::unique_ptr<Evaluator::SetterData> *resultSetterData, std::list<EvalStackEntry> &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<ICorDebugValue> 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<ICorDebugValue> 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<ICorDebugValue> iCorValue2;
-        IfFailRet(GetFrontStackEntryValue(&iCorValue2, evalStack, ed, output));
+        IfFailRet(GetFrontStackEntryValue(&iCorValue2, nullptr, evalStack, ed, output));
         evalStack.pop_front();
         ToRelease<ICorDebugValue> iCorRealValue2;
         CorElementType elemType2;
         IfFailRet(GetRealValueWithType(iCorValue2, &iCorRealValue2, &elemType2));
 
         ToRelease<ICorDebugValue> iCorValue1;
-        IfFailRet(GetFrontStackEntryValue(&iCorValue1, evalStack, ed, output));
+        IfFailRet(GetFrontStackEntryValue(&iCorValue1, nullptr, evalStack, ed, output));
         evalStack.front().ResetEntry();
         ToRelease<ICorDebugValue> iCorRealValue1;
         CorElementType elemType1;
@@ -980,7 +987,7 @@ namespace
     {
         HRESULT Status;
         ToRelease<ICorDebugValue> iCorValue;
-        IfFailRet(GetFrontStackEntryValue(&iCorValue, evalStack, ed, output));
+        IfFailRet(GetFrontStackEntryValue(&iCorValue, nullptr, evalStack, ed, output));
         evalStack.front().ResetEntry(EvalStackEntry::ResetLiteralStatus::No);
         ToRelease<ICorDebugValue> iCorRealValue;
         CorElementType elemType;
@@ -1067,7 +1074,7 @@ namespace
         std::vector<ToRelease<ICorDebugValue>> 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<ICorDebugValue> iCorValue;
         ToRelease<ICorDebugType> 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<ICorDebugValue> iCorArrayValue;
-        IfFailRet(GetFrontStackEntryValue(&iCorArrayValue, evalStack, ed, output));
+        std::unique_ptr<Evaluator::SetterData> 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<ICorDebugValue> iCorArrayValue;
-        IfFailRet(GetFrontStackEntryValue(&iCorArrayValue, evalStack, ed, output));
+        std::unique_ptr<Evaluator::SetterData> setterData;
+        IfFailRet(GetFrontStackEntryValue(&iCorArrayValue, &setterData, evalStack, ed, output));
 
         ToRelease<ICorDebugReferenceValue> 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<ICorDebugValue> iCorValue;
-        IfFailRet(GetFrontStackEntryValue(&iCorValue, evalStack, ed, output));
+        std::unique_ptr<Evaluator::SetterData> setterData;
+        IfFailRet(GetFrontStackEntryValue(&iCorValue, &setterData, evalStack, ed, output));
         evalStack.front().iCorValue = iCorValue.Detach();
         evalStack.front().identifiers.clear();
+        evalStack.front().setterData = std::move(setterData);
 
         ToRelease<ICorDebugReferenceValue> pReferenceValue;
         IfFailRet(evalStack.front().iCorValue->QueryInterface(IID_ICorDebugReferenceValue, (LPVOID*) &pReferenceValue));
@@ -1646,7 +1659,7 @@ namespace
         ToRelease<ICorDebugValue> iCorRealValueRightOp;
         ToRelease<ICorDebugValue> 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<ICorDebugValue> iCorRealValueLeftOp;
         ToRelease<ICorDebugValue> 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<EvalStackEntry> &evalStack, std::string &output)
 {
     static const std::vector<std::function<HRESULT(std::list<EvalStackEntry>&, 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<Evaluator::SetterData> *resultSetterData)
+{
+    HRESULT Status;
+    std::list<EvalStackEntry> 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<Evaluator::SetterData> setterData;
+    IfFailRet(GetFrontStackEntryValue(ppResultValue, &setterData, evalStack, m_evalData, output));
 
-        ToRelease<ICorDebugValue> 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<EvalStackEntry> evalStack;
+    IfFailRet(Run(pThread, frameLevel, evalFlags, expression, evalStack, output));
+
+    assert(evalStack.size() == 1);
+
+    ToRelease<ICorDebugValue> iCorValue;
+    IfFailRet(GetFrontStackEntryValue(&iCorValue, nullptr, evalStack, m_evalData, output));
+
+    return ImplicitCast(iCorValue, pValue, evalStack.front().literal, m_evalData);
 }
 
 HRESULT EvalStackMachine::FindPredefinedTypes(ICorDebugModule *pModule)
index 0755d7795a24fe93bb952e6c791ad563f60362f0..71d3c44ee0aeff00ae6210194ba0c7697e7343ed 100644 (file)
 #include <unordered_map>\r
 #include "interfaces/types.h"\r
 #include "utils/torelease.h"\r
+#include "debugger/evaluator.h"\r
 \r
 namespace netcoredbg\r
 {\r
 \r
-class Evaluator;\r
 class EvalHelpers;\r
 class EvalWaiter;\r
 \r
@@ -44,6 +44,9 @@ struct EvalStackEntry
     bool literal;\r
     // This entry is real variable (not literal, not result of expression calculation, not result of function call, ...).\r
     bool editable;\r
+    // In case iCorValue is editable and property, we need extra data in order to set value.\r
+    // Note, this data directly connected with `iCorValue` and could be available only in case `editable` is true.\r
+    std::unique_ptr<Evaluator::SetterData> setterData;\r
 \r
     EvalStackEntry() : preventBinding(false), literal(false), editable(false)\r
     {}\r
@@ -57,6 +60,7 @@ struct EvalStackEntry
         if (resetLiteral == ResetLiteralStatus::Yes)\r
             literal = false;\r
         editable = false;\r
+        setterData.reset();\r
     }\r
 };\r
 \r
@@ -85,9 +89,12 @@ class EvalStackMachine
     std::shared_ptr<Evaluator> m_sharedEvaluator;\r
     std::shared_ptr<EvalHelpers> m_sharedEvalHelpers;\r
     std::shared_ptr<EvalWaiter> m_sharedEvalWaiter;\r
-    std::list<EvalStackEntry> m_evalStack;\r
     EvalData m_evalData;\r
 \r
+    // Run stack machine for particular expression.\r
+    HRESULT Run(ICorDebugThread *pThread, FrameLevel frameLevel, int evalFlags, const std::string &expression,\r
+                std::list<EvalStackEntry> &evalStack, std::string &output);\r
+\r
 public:\r
 \r
     void SetupEval(std::shared_ptr<Evaluator> &sharedEvaluator, std::shared_ptr<EvalHelpers> &sharedEvalHelpers, std::shared_ptr<EvalWaiter> &sharedEvalWaiter)\r
@@ -100,9 +107,13 @@ public:
         m_evalData.pEvalWaiter = m_sharedEvalWaiter.get();\r
     }\r
 \r
-    // Run stack machine for particular expression.\r
-    HRESULT Run(ICorDebugThread *pThread, FrameLevel frameLevel, int evalFlags, const std::string &expression,\r
-                ICorDebugValue **ppResultValue, bool *editable, std::string &output);\r
+    // Evaluate expression. Optional, return `editable` state and in case result is property - setter related information.\r
+    HRESULT EvaluateExpression(ICorDebugThread *pThread, FrameLevel frameLevel, int evalFlags, const std::string &expression, ICorDebugValue **ppResultValue,\r
+                               std::string &output, bool *editable = nullptr, std::unique_ptr<Evaluator::SetterData> *resultSetterData = nullptr);\r
+\r
+    // Set value in pValue by expression with implicitly cast expression result to pValue type, if need.\r
+    HRESULT SetValueByExpression(ICorDebugThread *pThread, FrameLevel frameLevel, int evalFlags, ICorDebugValue *pValue,\r
+                                 const std::string &expression, std::string &output);\r
 \r
     // Find ICorDebugClass objects for all predefined types we need for stack machine during Private.CoreLib load.\r
     // See ManagedCallback::LoadModule().\r
index d44333088184102384906d5e10f6d3fb2546f775..318c9245ec7049cf6fbfba9d598310afb163a2e5 100644 (file)
@@ -54,6 +54,7 @@ HRESULT Evaluator::FollowFields(ICorDebugThread *pThread,
                                 std::vector<std::string> &identifiers,
                                 int nextIdentifier,
                                 ICorDebugValue **ppResult,
+                                std::unique_ptr<SetterData> *resultSetterData,
                                 int evalFlags)
 {
     HRESULT Status;
@@ -71,12 +72,12 @@ HRESULT Evaluator::FollowFields(ICorDebugThread *pThread,
 
         ToRelease<ICorDebugValue> 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<std::string> &identifiers,
                                          ICorDebugValue **ppResult,
+                                         std::unique_ptr<SetterData> *resultSetterData,
                                          int evalFlags)
 {
     HRESULT Status;
@@ -147,7 +151,7 @@ HRESULT Evaluator::FollowNestedFindValue(ICorDebugThread *pThread,
             ToRelease<ICorDebugValue> 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<ICorDebugValue> 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<std::string> &identifiers,
                                       ICorDebugValue **ppResultValue,
+                                      std::unique_ptr<SetterData> *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<ICorDebugValue> 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<ICorDebugValue> 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<ICorDebugValue> 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<ICorDebugArrayValue> 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<ICorDebugValue> 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<ICorDebugValue> 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<ICorDebugFunction> iCorFunc;
-                IfFailRet(pModule->GetFunctionFromToken(mdSetter, &iCorFunc));
-
-                ToRelease<ICorDebugValue> 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<ICorDebugFunction> 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)
index ed79e9b069859fcd08c5def32a8be02cd295ae22..77e37e8b232f08a62a09f51ba70387eafca24c90 100644 (file)
@@ -37,9 +37,35 @@ public:
     };
     typedef ArgElementType ReturnElementType;
 
+    struct SetterData
+    {
+        ToRelease<ICorDebugValue> thisValue;
+        ToRelease<ICorDebugFunction> 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<HRESULT(ICorDebugValue**,int)> GetValueCallback;
-    typedef std::function<HRESULT(const std::string&,std::string&,int)> SetValueCallback;
-    typedef std::function<HRESULT(ICorDebugType*,bool,const std::string&,GetValueCallback,SetValueCallback)> WalkMembersCallback;
+    typedef std::function<HRESULT(ICorDebugType*,bool,const std::string&,GetValueCallback,SetterData*)> WalkMembersCallback;
     typedef std::function<HRESULT(const std::string&,GetValueCallback)> WalkStackVarsCallback;
     typedef std::function<HRESULT(ICorDebugFunction**)> GetFunctionCallback;
     typedef std::function<HRESULT(bool,const std::string&,ReturnElementType&,std::vector<ArgElementType>&,GetFunctionCallback)> WalkMethodsCallback;
@@ -63,8 +89,10 @@ public:
         ICorDebugThread *pThread,
         FrameLevel frameLevel,
         ICorDebugValue *pInputValue,
+        SetterData *inputSetterData,
         std::vector<std::string> &identifiers,
         ICorDebugValue **ppResultValue,
+        std::unique_ptr<SetterData> *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<Modules> m_sharedModules;
@@ -101,6 +133,7 @@ private:
         const std::string &methodClass,
         std::vector<std::string> &identifiers,
         ICorDebugValue **ppResult,
+        std::unique_ptr<SetterData> *resultSetterData,
         int evalFlags);
 
     HRESULT FollowFields(
@@ -111,6 +144,7 @@ private:
         std::vector<std::string> &identifiers,
         int nextIdentifier,
         ICorDebugValue **ppResult,
+        std::unique_ptr<SetterData> *resultSetterData,
         int evalFlags);
 
     HRESULT WalkMembers(
@@ -118,6 +152,7 @@ private:
         ICorDebugThread *pThread,
         FrameLevel frameLevel,
         ICorDebugType *pTypeCast,
+        bool provideSetterData,
         WalkMembersCallback cb);
 };
 
index 8e996c3a5971435978cbc587961ecf608aa129ca..ab1216a57867ecb514f009dfc6ff4a3c2f97f08c 100644 (file)
@@ -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<ICorDebugValue> 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);
 }
 
 
index e283dfafa1823e997baf4bdf8ff1bee0e385174b..73d8d47aa243f810ebe8e78ef287767da52536dd 100644 (file)
@@ -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;
index 885a37c0e2c6d7028a4321a5d80cc246e211357f..ffb1dcd2572d043db9fabb551b48a95626e8a77e 100644 (file)
@@ -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<ICorDebugValue> 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<ICorDebugValue> 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<ICorDebugValue> 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<ICorDebugThread> 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<ICorDebugValue> 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<ICorDebugThread> pThread;
     IfFailRet(pProcess->GetThread(int(threadId), &pThread));
 
-    IfFailRet(m_sharedEvalStackMachine->Run(pThread, frameId.getLevel(), evalFlags, value, &pVariable, nullptr, output));
-    IfFailRet(PrintValue(pVariable, output));
+    ToRelease<ICorDebugValue> iCorValue;
+    bool editable = false;
+    std::unique_ptr<Evaluator::SetterData> 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;
 }
 
index e4aa97781de0416d6578bb6ae8fe75f045735fd9..9f05013b7ce3c0eddf8ad52c8ea4535bb0f2a56f 100644 (file)
@@ -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,
index ae233681ece7a677a2ec168470f12e2ab1ecb588..f3885e13678a2d55862ae2e41016fd1ce5c73341 100644 (file)
@@ -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;
index b8dd1c677e9957fe04f1d2f754c11c5950702464..b75a79d15f3b3b0d6245b018b947a36e61d3be0d 100644 (file)
@@ -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) + "\"";
 
index 47194dbf0db8a64a5ac478eb201c839854bda77c..692978d947a1d71f48c658309accb0719ae36d05 100644 (file)
@@ -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())
index 79cf3c91c64f2d04efc44b21783f5cffb99411e4..124632c12c2a043999c22f78e20e81b87fe41f8a 100644 (file)
@@ -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__");
             });
index e4ee0862b400ef8eebefe8c23f4d217d6476273e..70220481f16e4130ce3dd81de03c4161c39bef4d 100644 (file)
@@ -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__");
             });