Debugger: Implement first part of #11387.

VariablesView:
- The view now keeps a mapping of a list of expressions associated
  with functions.
- Add actions for adding/removing expressions to variables context menu.
- When setting up to show a new stack frame, also add corresponding expression
  nodes and request their evaluation.
- Extend VariablesView::Listener interface to also encompass expression
  evaluation requests.
- Don't add context actions for expression nodes.

TeamWindow:
- Implement VariablesView::Listener expression evaluation hook and forward
  responses along.
This commit is contained in:
Rene Gollent
2014-11-08 11:00:27 -05:00
parent 11832b28af
commit b7e72db3cc
4 changed files with 586 additions and 57 deletions
@@ -58,6 +58,7 @@
#include "TypeComponentPath.h"
#include "UiUtils.h"
#include "UserInterface.h"
#include "Value.h"
#include "Variable.h"
#include "WatchPromptWindow.h"
@@ -906,6 +907,20 @@ TeamWindow::ValueNodeValueRequested(CpuState* cpuState,
}
void
TeamWindow::ExpressionEvaluationRequested(const char* expression,
type_code resultType, StackFrame* frame, ::Thread* thread)
{
SourceLanguage* language;
if (_GetActiveSourceLanguage(language) != B_OK)
return;
BReference<SourceLanguage> languageReference(language, true);
fListener->ExpressionEvaluationRequested(language, expression, resultType,
frame, thread);
}
void
TeamWindow::ThreadStateChanged(const Team::ThreadEvent& event)
{
@@ -976,6 +991,32 @@ TeamWindow::WatchpointChanged(const Team::WatchpointEvent& event)
}
void
TeamWindow::ExpressionEvaluated(const Team::ExpressionEvaluationEvent& event)
{
BMessage message(MSG_EXPRESSION_EVALUATED);
if (message.AddString("expression", event.GetExpression()) != B_OK
|| message.AddInt32("result", event.GetResult()) != B_OK) {
return;
}
BReference<Value> reference;
Value* value = event.GetValue();
if (value != NULL) {
if (message.AddPointer("value", value) != B_OK)
return;
reference.SetTo(value);
}
// currently, the only circumstance in which TeamWindow cares about
// expression evaluation results is when handling them on behalf of
// VariablesView. As such, simply forward them on.
BMessenger messenger(fVariablesView);
if (messenger.SendMessage(&message) == B_OK)
reference.Detach();
}
void
TeamWindow::DebugReportChanged(const Team::DebugReportEvent& event)
{
@@ -127,6 +127,11 @@ private:
virtual void ValueNodeValueRequested(CpuState* cpuState,
ValueNodeContainer* container,
ValueNode* valueNode);
virtual void ExpressionEvaluationRequested(
const char* expression,
type_code resultType,
StackFrame* frame,
::Thread* thread);
// Team::Listener
virtual void ThreadStateChanged(
@@ -143,9 +148,13 @@ private:
const Team::UserBreakpointEvent& event);
virtual void WatchpointChanged(
const Team::WatchpointEvent& event);
virtual void ExpressionEvaluated(
const Team::ExpressionEvaluationEvent&
event);
virtual void DebugReportChanged(
const Team::DebugReportEvent& event);
// Function::Listener
virtual void FunctionSourceCodeChanged(Function* function);
@@ -25,6 +25,9 @@
#include "ActionMenuItem.h"
#include "Architecture.h"
#include "ExpressionInfo.h"
#include "ExpressionValueNode.h"
#include "ExpressionValues.h"
#include "FileSourceCode.h"
#include "Function.h"
#include "FunctionID.h"
@@ -38,6 +41,7 @@
#include "StackTrace.h"
#include "StackFrame.h"
#include "StackFrameValues.h"
#include "SyntheticPrimitiveType.h"
#include "TableCellValueRenderer.h"
#include "Team.h"
#include "TeamDebugInfo.h"
@@ -67,7 +71,9 @@ enum {
enum {
MSG_MODEL_NODE_HIDDEN = 'monh',
MSG_VALUE_NODE_NEEDS_VALUE = 'mvnv',
MSG_RESTORE_PARTIAL_VIEW_STATE = 'mpvs'
MSG_RESTORE_PARTIAL_VIEW_STATE = 'mpvs',
MSG_ADD_WATCH_EXPRESSION = 'awex',
MSG_REMOVE_WATCH_EXPRESSION = 'rwex'
};
@@ -75,6 +81,106 @@ enum {
static const uint64 kMaxArrayElementCount = 10;
// #pragma mark - FunctionKey
struct VariablesView::FunctionKey {
FunctionID* function;
FunctionKey(FunctionID* function)
:
function(function)
{
}
uint32 HashValue() const
{
return function->HashValue();
}
bool operator==(const FunctionKey& other) const
{
return *function == *other.function;
}
};
// #pragma mark - ExpressionInfoEntry
struct VariablesView::ExpressionInfoEntry : FunctionKey, ExpressionInfoList {
ExpressionInfoEntry* next;
ExpressionInfoEntry(FunctionID* function)
:
FunctionKey(function),
ExpressionInfoList(10, false)
{
function->AcquireReference();
}
~ExpressionInfoEntry()
{
_Cleanup();
}
void SetInfo(const ExpressionInfoList& infoList)
{
_Cleanup();
for (int32 i = 0; i < infoList.CountItems(); i++) {
ExpressionInfo* info = infoList.ItemAt(i);
if (!AddItem(info))
break;
info->AcquireReference();
}
}
private:
void _Cleanup()
{
for (int32 i = 0; i < CountItems(); i++)
ItemAt(i)->ReleaseReference();
MakeEmpty();
}
};
// #pragma mark - ExpressionInfoEntryHashDefinition
struct VariablesView::ExpressionInfoEntryHashDefinition {
typedef FunctionKey KeyType;
typedef ExpressionInfoEntry ValueType;
size_t HashKey(const FunctionKey& key) const
{
return key.HashValue();
}
size_t Hash(const ExpressionInfoEntry* value) const
{
return value->HashValue();
}
bool Compare(const FunctionKey& key,
const ExpressionInfoEntry* value) const
{
return key == *value;
}
ExpressionInfoEntry*& GetLink(ExpressionInfoEntry* value) const
{
return value->next;
}
};
// #pragma mark - ContainerListener
class VariablesView::ContainerListener : public ValueNodeContainer::Listener {
public:
ContainerListener(BHandler* indirectTarget);
@@ -99,6 +205,9 @@ private:
};
// #pragma mark - ModelNode
class VariablesView::ModelNode : public BReferenceable {
public:
ModelNode(ModelNode* parent, Variable* variable, ValueNodeChild* nodeChild,
@@ -377,6 +486,7 @@ private:
bool fIsPresentationNode;
bool fHidden;
bool fValueChanged;
bool fIsExpression;
public:
ModelNode* fNext;
@@ -483,6 +593,9 @@ public:
const TreeTablePath& path,
int32 columnIndex, BToolTip** _tip);
status_t AddSyntheticNode(ModelNode* node);
void RemoveSyntheticNode(ModelNode* node);
private:
struct NodeHashDefinition {
typedef ValueNodeChild* KeyType;
@@ -1353,6 +1466,47 @@ VariablesView::VariableTableModel::GetToolTipForTablePath(
}
status_t
VariablesView::VariableTableModel::AddSyntheticNode(ModelNode* node)
{
status_t error = node->Init();
if (error != B_OK)
return error;
int32 index = fNodes.CountItems();
if (!fNodes.AddItem(node)) {
return B_NO_MEMORY;
// NB: we take over the caller's reference
}
fNodeTable.Insert(node);
node->NodeChild()->Node()->SetContainer(fNodeManager->GetContainer());
NotifyNodesAdded(TreeTablePath(), index, 1);
return B_OK;
}
void
VariablesView::VariableTableModel::RemoveSyntheticNode(ModelNode* node)
{
int32 index = fNodes.IndexOf(node);
if (index < 0)
return;
fNodeTable.Remove(node);
fNodes.RemoveItemAt(index);
NotifyNodesRemoved(TreeTablePath(), index, 1);
node->ReleaseReference();
}
status_t
VariablesView::VariableTableModel::_AddNode(Variable* variable,
ModelNode* parent, ValueNodeChild* nodeChild, bool isPresentationNode,
@@ -1460,6 +1614,7 @@ VariablesView::VariablesView(Listener* listener)
fContainerListener(NULL),
fPreviousViewState(NULL),
fViewStateHistory(NULL),
fExpressions(NULL),
fTableCellContextMenuTracker(NULL),
fFrameClearPending(false),
fListener(listener)
@@ -1539,6 +1694,8 @@ VariablesView::SetStackFrame(Thread* thread, StackFrame* stackFrame)
ModelNode* node = (ModelNode*)fVariableTableModel->ChildAt(root, i);
_RequestNodeValue(node);
}
_RestoreExpressionNodes();
}
_RestoreViewState();
@@ -1759,6 +1916,66 @@ VariablesView::MessageReceived(BMessage* message)
Looper()->PostMessage(&looperMessage);
break;
}
case MSG_ADD_WATCH_EXPRESSION:
{
BMessage looperMessage(MSG_SHOW_EXPRESSION_PROMPT_WINDOW);
looperMessage.AddPointer("target", this);
Looper()->PostMessage(&looperMessage);
break;
}
case MSG_REMOVE_WATCH_EXPRESSION:
{
ModelNode* node;
if (message->FindPointer("node", reinterpret_cast<void**>(&node))
!= B_OK) {
break;
}
_RemoveExpression(node);
break;
}
case MSG_ADD_NEW_EXPRESSION:
{
const char* expression;
int32 type;
Type* resultType;
if (message->FindString("expression", &expression) != B_OK
|| message->FindInt32("type", &type) != B_OK
|| _GetTypeForTypeCode(type, resultType) != B_OK) {
break;
}
BReference<Type> typeReference(resultType, true);
status_t error = _AddExpression(expression, resultType);
if (error != B_OK) {
// TODO: notify user of failure
break;
}
fListener->ExpressionEvaluationRequested(expression, type,
fStackFrame, fThread);
break;
}
case MSG_EXPRESSION_EVALUATED:
{
const char* expression;
status_t result;
Value* value = NULL;
if (message->FindString("expression", &expression) != B_OK
|| message->FindInt32("result", &result) != B_OK) {
break;
}
BReference<Value> valueReference;
if (message->FindPointer("value", reinterpret_cast<void**>(&value))
== B_OK) {
valueReference.SetTo(value, true);
}
_SetExpressionNodeValue(expression, result, value);
break;
}
case MSG_VALUE_NODE_CHANGED:
{
ValueNodeChild* nodeChild;
@@ -1980,19 +2197,23 @@ VariablesView::TreeTableCellMouseDown(TreeTable* table,
TableCellContextMenuTracker(node, Looper(), this);
BReference<TableCellContextMenuTracker> trackerReference(tracker);
ContextActionList* preActionList = new(std::nothrow) ContextActionList;
if (preActionList == NULL)
ContextActionList* preActionList;
ContextActionList* postActionList;
error = _GetContextActionsForNode(node, preActionList, postActionList);
if (error != B_OK)
return;
BPrivate::ObjectDeleter<ContextActionList> preActionListDeleter(
preActionList);
error = _GetContextActionsForNode(node, preActionList);
if (error != B_OK)
return;
BPrivate::ObjectDeleter<ContextActionList> postActionListDeleter(
postActionList);
if (tracker == NULL || tracker->Init(settings, settingsMenu, preActionList) != B_OK)
if (tracker == NULL || tracker->Init(settings, settingsMenu, preActionList,
postActionList) != B_OK) {
return;
}
fTableCellContextMenuTracker = trackerReference.Detach();
fTableCellContextMenuTracker->ShowMenu(screenWhere);
@@ -2028,6 +2249,10 @@ VariablesView::_Init()
fViewStateHistory = new VariablesViewStateHistory;
if (fViewStateHistory->Init() != B_OK)
throw std::bad_alloc();
fExpressions = new ExpressionInfoTable();
if (fExpressions->Init() != B_OK)
throw std::bad_alloc();
}
@@ -2077,73 +2302,108 @@ VariablesView::_RequestNodeValue(ModelNode* node)
status_t
VariablesView::_GetContextActionsForNode(ModelNode* node,
ContextActionList* actions)
ContextActionList*& _preActions, ContextActionList*& _postActions)
{
_preActions = NULL;
_postActions = NULL;
ValueLocation* location = node->NodeChild()->Location();
if (location == NULL)
return B_OK;
_preActions = new(std::nothrow) ContextActionList;
if (_preActions == NULL)
return B_NO_MEMORY;
BPrivate::ObjectDeleter<ContextActionList> preActionListDeleter(
_preActions);
status_t result = B_OK;
BMessage* message = NULL;
// only show the Inspect option if the value is in fact located
// in memory.
if (location->PieceAt(0).type == VALUE_PIECE_LOCATION_MEMORY) {
result = _AddContextAction("Inspect", MSG_SHOW_INSPECTOR_WINDOW,
actions, message);
if (result != B_OK)
return result;
message->AddUInt64("address", location->PieceAt(0).address);
}
ValueNode* valueNode = node->NodeChild()->Node();
if (valueNode != NULL) {
AddressType* type = dynamic_cast<AddressType*>(valueNode->GetType());
if (type != NULL && type->BaseType() != NULL) {
result = _AddContextAction("Cast to array", MSG_TYPECAST_TO_ARRAY,
actions, message);
if (location != NULL) {
if (location->PieceAt(0).type == VALUE_PIECE_LOCATION_MEMORY) {
result = _AddContextAction("Inspect", MSG_SHOW_INSPECTOR_WINDOW,
_preActions, message);
if (result != B_OK)
return result;
message->AddUInt64("address", location->PieceAt(0).address);
}
ValueNode* valueNode = node->NodeChild()->Node();
if (valueNode != NULL) {
AddressType* type = dynamic_cast<AddressType*>(valueNode->GetType());
if (type != NULL && type->BaseType() != NULL) {
result = _AddContextAction("Cast to array", MSG_TYPECAST_TO_ARRAY,
_preActions, message);
if (result != B_OK)
return result;
message->AddPointer("node", node);
}
}
result = _AddContextAction("Cast as" B_UTF8_ELLIPSIS,
MSG_SHOW_TYPECAST_NODE_PROMPT, _preActions, message);
if (result != B_OK)
return result;
result = _AddContextAction("Watch" B_UTF8_ELLIPSIS,
MSG_SHOW_WATCH_VARIABLE_PROMPT, _preActions, message);
if (result != B_OK)
return result;
if (valueNode == NULL)
return B_OK;
if (valueNode->LocationAndValueResolutionState() == B_OK) {
result = _AddContextAction("Copy Value", B_COPY, _preActions, message);
if (result != B_OK)
return result;
}
bool addRangedContainerItem = false;
// if the current node isn't itself a ranged container, check if it
// contains a hidden node which is, since in the latter case we
// want to present the range selection as well.
if (valueNode->IsRangedContainer())
addRangedContainerItem = true;
else if (node->CountChildren() == 1 && node->ChildAt(0)->IsHidden()) {
valueNode = node->ChildAt(0)->NodeChild()->Node();
if (valueNode != NULL && valueNode->IsRangedContainer())
addRangedContainerItem = true;
}
if (addRangedContainerItem) {
result = _AddContextAction("Set visible range" B_UTF8_ELLIPSIS,
MSG_SHOW_CONTAINER_RANGE_PROMPT, _preActions, message);
if (result != B_OK)
return result;
message->AddPointer("node", node);
}
}
result = _AddContextAction("Cast as" B_UTF8_ELLIPSIS,
MSG_SHOW_TYPECAST_NODE_PROMPT, actions, message);
_postActions = new(std::nothrow) ContextActionList;
if (_postActions == NULL)
return B_NO_MEMORY;
BPrivate::ObjectDeleter<ContextActionList> postActionListDeleter(
_postActions);
result = _AddContextAction("Add watch expression" B_UTF8_ELLIPSIS,
MSG_ADD_WATCH_EXPRESSION, _postActions, message);
if (result != B_OK)
return result;
result = _AddContextAction("Watch" B_UTF8_ELLIPSIS,
MSG_SHOW_WATCH_VARIABLE_PROMPT, actions, message);
if (result != B_OK)
return result;
if (valueNode == NULL)
return B_OK;
if (valueNode->LocationAndValueResolutionState() == B_OK) {
result = _AddContextAction("Copy Value", B_COPY, actions, message);
if (dynamic_cast<ExpressionValueNodeChild*>(node->NodeChild()) != NULL) {
result = _AddContextAction("Remove watch expression",
MSG_REMOVE_WATCH_EXPRESSION, _postActions, message);
if (result != B_OK)
return result;
message->AddPointer("node", node);
}
// if the current node isn't itself a ranged container, check if it
// contains a hidden node which is, since in the latter case we
// want to present the range selection as well.
if (!valueNode->IsRangedContainer()) {
if (node->CountChildren() == 1 && node->ChildAt(0)->IsHidden()) {
valueNode = node->ChildAt(0)->NodeChild()->Node();
if (valueNode == NULL || !valueNode->IsRangedContainer())
return B_OK;
} else
return B_OK;
}
result = _AddContextAction("Set visible range" B_UTF8_ELLIPSIS,
MSG_SHOW_CONTAINER_RANGE_PROMPT, actions, message);
if (result != B_OK)
return result;
preActionListDeleter.Detach();
postActionListDeleter.Detach();
return B_OK;
}
@@ -2286,7 +2546,13 @@ VariablesView::_AddViewStateDescendentNodeInfos(VariablesViewState* viewState,
nodeInfo.SetRendererSettings(settings->Message());
}
ObjectID* id = node->GetVariable()->ID();
Variable* variable = node->GetVariable();
if (variable == NULL) {
// ignore synthetic nodes
continue;
}
ObjectID* id = variable->ID();
TypeComponentPath* componentPath = node->GetPath();
status_t error = viewState->SetNodeInfo(id, componentPath, nodeInfo);
@@ -2326,6 +2592,11 @@ VariablesView::_ApplyViewStateDescendentNodeInfos(VariablesViewState* viewState,
return B_NO_MEMORY;
// apply the node's info, if any
Variable* variable = node->GetVariable();
if (variable == NULL) {
// ignore synthetic nodes
return B_OK;
}
ObjectID* objectID = node->GetVariable()->ID();
TypeComponentPath* componentPath = node->GetPath();
const VariablesViewNodeInfo* nodeInfo = viewState->GetNodeInfo(
@@ -2392,6 +2663,183 @@ VariablesView::_CopyVariableValueToClipboard()
}
status_t
VariablesView::_AddExpression(const char* expression, Type* resultType)
{
// if our stack frame doesn't have an associated function,
// we can't add an expression
FunctionInstance* function = fStackFrame->Function();
if (function == NULL)
return B_NOT_ALLOWED;
FunctionID* id = function->GetFunctionID();
if (id == NULL)
return B_NO_MEMORY;
BReference<FunctionID> idReference(id, true);
ExpressionInfoEntry* entry = fExpressions->Lookup(FunctionKey(id));
if (entry == NULL) {
entry = new(std::nothrow) ExpressionInfoEntry(id);
if (entry == NULL)
return B_NO_MEMORY;
status_t error = fExpressions->Insert(entry);
if (error != B_OK) {
delete entry;
return error;
}
}
ExpressionInfo* info = new(std::nothrow) ExpressionInfo(expression,
resultType);
if (info == NULL)
return B_NO_MEMORY;
BReference<ExpressionInfo> infoReference(info, true);
status_t error = _AddExpressionNode(*info);
if (error != B_OK)
return error;
if (!entry->AddItem(info))
return B_NO_MEMORY;
infoReference.Detach();
return B_OK;
}
void
VariablesView::_RemoveExpression(ModelNode* node)
{
ExpressionValueNodeChild* child
= dynamic_cast<ExpressionValueNodeChild*>(node->NodeChild());
if (child == NULL)
return;
FunctionID* id = fStackFrame->Function()->GetFunctionID();
BReference<FunctionID> idReference(id, true);
ExpressionInfoEntry* entry = fExpressions->Lookup(FunctionKey(id));
if (entry == NULL)
return;
for (int32 i = 0; i < entry->CountItems(); i++) {
ExpressionInfo* info = entry->ItemAt(i);
if (info->Expression() == child->GetExpression()) {
entry->RemoveItemAt(i);
info->ReleaseReference();
break;
}
}
fVariableTableModel->RemoveSyntheticNode(node);
}
status_t
VariablesView::_AddExpressionNode(const ExpressionInfo& info)
{
Type* type = info.ResultType();
ExpressionValueNodeChild* child
= new(std::nothrow) ExpressionValueNodeChild(info.Expression(), type);
if (child == NULL)
return B_NO_MEMORY;
BReference<ValueNodeChild> childReference(child, true);
ExpressionValueNode* expressionNode
= new(std::nothrow) ExpressionValueNode(child, type);
if (expressionNode == NULL)
return B_NO_MEMORY;
BReference<ValueNode> expressionNodeReference(expressionNode, true);
child->SetNode(expressionNode);
ModelNode* modelNode = new(std::nothrow) ModelNode(NULL, NULL,
child, true);
if (modelNode == NULL)
return B_NO_MEMORY;
BReference<ModelNode> modelNodeReference(modelNode, true);
status_t error = fVariableTableModel->AddSyntheticNode(modelNode);
if (error != B_OK)
return error;
expressionNodeReference.Detach();
modelNodeReference.Detach();
return B_OK;
}
void
VariablesView::_RestoreExpressionNodes()
{
FunctionID* id = fStackFrame->Function()->GetFunctionID();
BReference<FunctionID> idReference(id, true);
ExpressionInfoEntry* entry = fExpressions->Lookup(FunctionKey(id));
if (entry == NULL)
return;
for (int32 i = 0; i < entry->CountItems(); i++) {
ExpressionInfo* info = entry->ItemAt(i);
_AddExpressionNode(*info);
SyntheticPrimitiveType* type
= dynamic_cast<SyntheticPrimitiveType*>(info->ResultType());
fListener->ExpressionEvaluationRequested(info->Expression(),
type->TypeConstant(), fStackFrame, fThread);
}
}
void
VariablesView::_SetExpressionNodeValue(const char* expression,
status_t finalResult, Value* value)
{
FunctionID* id = fStackFrame->Function()->GetFunctionID();
BReference<FunctionID> idReference(id, true);
ExpressionInfoEntry* entry = fExpressions->Lookup(FunctionKey(id));
if (entry == NULL)
return;
void* rootNode = fVariableTableModel->Root();
for (int32 i = 0; i < fVariableTableModel->CountChildren(rootNode); i++) {
ModelNode* node = (ModelNode*)fVariableTableModel->ChildAt(rootNode,
i);
ExpressionValueNodeChild* child
= dynamic_cast<ExpressionValueNodeChild*>(node->NodeChild());
if (child == NULL)
continue;
if (child->GetExpression() != expression)
continue;
child->Node()->SetLocationAndValue(NULL, value, finalResult);
return;
}
}
status_t
VariablesView::_GetTypeForTypeCode(int32 type, Type*& _resultType) const
{
if (BVariant::TypeIsNumber(type)) {
_resultType = new(std::nothrow) SyntheticPrimitiveType(type);
if (_resultType == NULL)
return B_NO_MEMORY;
return B_OK;
}
return B_NOT_SUPPORTED;
}
// #pragma mark - Listener
@@ -8,20 +8,22 @@
#include <GroupView.h>
#include <util/OpenHashTable.h>
#include "table/TreeTable.h"
class ActionMenuItem;
class CpuState;
class ExpressionInfo;
class SettingsMenu;
class StackFrame;
class StackFrameValues;
class Thread;
class Type;
class TypeComponentPath;
class ValueNode;
class ValueNodeContainer;
class Value;
class Variable;
class VariablesViewState;
class VariablesViewStateHistory;
@@ -68,13 +70,22 @@ private:
class ContextMenu;
class TableCellContextMenuTracker;
typedef BObjectList<ActionMenuItem> ContextActionList;
typedef BObjectList<ExpressionInfo> ExpressionInfoList;
struct FunctionKey;
struct ExpressionInfoEntry;
struct ExpressionInfoEntryHashDefinition;
typedef BOpenHashTable<ExpressionInfoEntryHashDefinition>
ExpressionInfoTable;
private:
void _Init();
void _RequestNodeValue(ModelNode* node);
status_t _GetContextActionsForNode(ModelNode* node,
ContextActionList* actions);
ContextActionList*& _preActions,
ContextActionList*& _postActions);
status_t _AddContextAction(const char* action,
uint32 what, ContextActionList* actions,
BMessage*& _message);
@@ -91,6 +102,19 @@ private:
TreeTablePath& path);
void _CopyVariableValueToClipboard();
status_t _AddExpression(const char* expression,
Type* resultType);
void _RemoveExpression(ModelNode* node);
status_t _AddExpressionNode(const ExpressionInfo& info);
void _RestoreExpressionNodes();
void _SetExpressionNodeValue(const char* expression,
status_t finalResult, Value* value);
status_t _GetTypeForTypeCode(int32 typeCode,
Type*& _resultType) const;
private:
Thread* fThread;
StackFrame* fStackFrame;
@@ -99,6 +123,7 @@ private:
ContainerListener* fContainerListener;
VariablesViewState* fPreviousViewState;
VariablesViewStateHistory* fViewStateHistory;
ExpressionInfoTable* fExpressions;
TableCellContextMenuTracker* fTableCellContextMenuTracker;
bool fFrameClearPending;
Listener* fListener;
@@ -112,6 +137,12 @@ public:
virtual void ValueNodeValueRequested(CpuState* cpuState,
ValueNodeContainer* container,
ValueNode* valueNode) = 0;
virtual void ExpressionEvaluationRequested(
const char* expression,
type_code resultType,
StackFrame* frame,
Thread* thread) = 0;
};