IdeDebugger: improve unfolding of watches. Allow Pointer to object/array to be unfolded (and dereference them for this)

This commit is contained in:
Martin 2023-06-11 14:30:46 +02:00
parent 9a0e268738
commit ea1e68ed26
3 changed files with 66 additions and 42 deletions

View File

@ -155,6 +155,9 @@ begin
end; end;
ResData := AWatchAbleResult.ResultData; ResData := AWatchAbleResult.ResultData;
while (ResData <> nil) and (ResData.ValueKind = rdkPointerVal) do
ResData := ResData.DerefData;
if (ResData <> nil) and if (ResData <> nil) and
(ResData.FieldCount > 0) and (ResData.FieldCount > 0) and
(ResData.ValueKind <> rdkConvertRes) (ResData.ValueKind <> rdkConvertRes)
@ -180,7 +183,7 @@ procedure TDbgTreeViewWatchDataMgr.DoUpdateArraySubItems(AWatchAble: TObject;
ChildCount: LongWord); ChildCount: LongWord);
var var
NewWatchAble: TObject; NewWatchAble: TObject;
i, TotalCount: Integer; i, TotalCount, DerefCount: Integer;
ResData: TWatchResultData; ResData: TWatchResultData;
ExistingNode, nd: PVirtualNode; ExistingNode, nd: PVirtualNode;
Nav: TArrayNavigationBar; Nav: TArrayNavigationBar;
@ -188,6 +191,11 @@ var
begin begin
ChildCount := 0; ChildCount := 0;
ResData := AWatchAbleResult.ResultData; ResData := AWatchAbleResult.ResultData;
DerefCount := 0;
while (ResData <> nil) and (ResData.ValueKind = rdkPointerVal) do begin
ResData := ResData.DerefData;
inc(DerefCount);
end;
if (ResData = nil) then if (ResData = nil) then
exit; exit;
@ -226,7 +234,7 @@ begin
Offs := Nav.Index; Offs := Nav.Index;
for i := 0 to ChildCount - 1 do begin for i := 0 to ChildCount - 1 do begin
NewWatchAble := AWatchAbleResult.ChildrenByNameAsArrayEntry[Offs + i]; NewWatchAble := AWatchAbleResult.ChildrenByNameAsArrayEntry[Offs + i, DerefCount];
if NewWatchAble = nil then begin if NewWatchAble = nil then begin
dec(ChildCount); dec(ChildCount);
continue; continue;
@ -265,9 +273,18 @@ var
AnchClass: String; AnchClass: String;
NewWatchAble: TObject; NewWatchAble: TObject;
ChildInfo: TWatchResultDataFieldInfo; ChildInfo: TWatchResultDataFieldInfo;
DerefCount: Integer;
begin begin
ChildCount := 0; ChildCount := 0;
ResData := AWatchAbleResult.ResultData; ResData := AWatchAbleResult.ResultData;
DerefCount := 0;
while (ResData <> nil) and (ResData.ValueKind = rdkPointerVal) do begin
ResData := ResData.DerefData;
inc(DerefCount);
end;
if ResData = nil then
exit;
ExistingNode := FTreeView.GetFirstChildNoInit(AVNode); ExistingNode := FTreeView.GetFirstChildNoInit(AVNode);
if ExistingNode <> nil then if ExistingNode <> nil then
FTreeView.NodeControl[ExistingNode].Free; FTreeView.NodeControl[ExistingNode].Free;
@ -276,7 +293,7 @@ begin
if ResData.StructType <> dstRecord then if ResData.StructType <> dstRecord then
AnchClass := ResData.TypeName; AnchClass := ResData.TypeName;
for ChildInfo in ResData do begin for ChildInfo in ResData do begin
NewWatchAble := AWatchAbleResult.ChildrenByNameAsField[ChildInfo.FieldName, AnchClass]; NewWatchAble := AWatchAbleResult.ChildrenByNameAsField[ChildInfo.FieldName, AnchClass, DerefCount];
if NewWatchAble = nil then begin if NewWatchAble = nil then begin
continue; continue;
end; end;
@ -318,9 +335,9 @@ begin
AnchClass := TypInfo.TypeName; AnchClass := TypInfo.TypeName;
for i := 0 to TypInfo.Fields.Count-1 do begin for i := 0 to TypInfo.Fields.Count-1 do begin
if IsGdbmiArray then if IsGdbmiArray then
NewWatchAble := AWatchAbleResult.ChildrenByNameAsArrayEntry[StrToInt64Def(TypInfo.Fields[i].Name, 0)] NewWatchAble := AWatchAbleResult.ChildrenByNameAsArrayEntry[StrToInt64Def(TypInfo.Fields[i].Name, 0), 0]
else else
NewWatchAble := AWatchAbleResult.ChildrenByNameAsField[TypInfo.Fields[i].Name, AnchClass]; NewWatchAble := AWatchAbleResult.ChildrenByNameAsField[TypInfo.Fields[i].Name, AnchClass, 0];
if NewWatchAble = nil then begin if NewWatchAble = nil then begin
dec(ChildCount); dec(ChildCount);
continue; continue;
@ -422,6 +439,7 @@ procedure TDbgTreeViewWatchDataMgr.UpdateWatchData(AWatchAble: TObject;
AnIgnoreNodeVisible: Boolean); AnIgnoreNodeVisible: Boolean);
var var
TypInfo: TDBGType; TypInfo: TDBGType;
ResData: TWatchResultData;
HasChildren: Boolean; HasChildren: Boolean;
c: LongWord; c: LongWord;
begin begin
@ -450,12 +468,15 @@ begin
((DebugBoss = nil) or (DebugBoss.State <> dsRun)) ((DebugBoss = nil) or (DebugBoss.State <> dsRun))
then begin then begin
TypInfo := AWatchAbleResult.TypeInfo; TypInfo := AWatchAbleResult.TypeInfo;
ResData := AWatchAbleResult.ResultData;
while (ResData <> nil) and (ResData.ValueKind = rdkPointerVal) do
ResData := ResData.DerefData;
HasChildren := ( (TypInfo <> nil) and (TypInfo.Fields <> nil) and (TypInfo.Fields.Count > 0) ) or HasChildren := ( (TypInfo <> nil) and (TypInfo.Fields <> nil) and (TypInfo.Fields.Count > 0) ) or
( (AWatchAbleResult.ResultData <> nil) and ( (ResData <> nil) and
( ( (AWatchAbleResult.ResultData.FieldCount > 0) and (AWatchAbleResult.ResultData.ValueKind <> rdkConvertRes) ) ( ( (ResData.FieldCount > 0) and (ResData.ValueKind <> rdkConvertRes) )
or or
//( (AWatchAbleResult.ResultData.ValueKind = rdkArray) and (AWatchAbleResult.ResultData.ArrayLength > 0) ) //( (ResData.ValueKind = rdkArray) and (ResData.ArrayLength > 0) )
(AWatchAbleResult.ResultData.ArrayLength > 0) (ResData.ArrayLength > 0)
) ); ) );
FTreeView.HasChildren[AVNode] := HasChildren; FTreeView.HasChildren[AVNode] := HasChildren;

View File

@ -534,8 +534,8 @@ type
TIdeWatchValue = class(TWatchValue, IWatchAbleResultIntf) TIdeWatchValue = class(TWatchValue, IWatchAbleResultIntf)
private private
function GetChildrenByNameAsArrayEntry(AName: Int64): TObject; // TIdeWatch; function GetChildrenByNameAsArrayEntry(AName: Int64; DerefCount: Integer): TObject; // TIdeWatch;
function GetChildrenByNameAsField(AName, AClassName: String): TObject; // TIdeWatch; function GetChildrenByNameAsField(AName, AClassName: String; DerefCount: Integer): TObject; // TIdeWatch;
function GetWatch: TIdeWatch; function GetWatch: TIdeWatch;
function GetEnabled: Boolean; function GetEnabled: Boolean;
protected protected
@ -566,8 +566,8 @@ type
function MaybeCopyResult(ASourceWatch: TIdeWatch): boolean; function MaybeCopyResult(ASourceWatch: TIdeWatch): boolean;
property ChildrenByNameAsField[AName, AClassName: String]: TObject read GetChildrenByNameAsField; property ChildrenByNameAsField[AName, AClassName: String; DerefCount: Integer]: TObject read GetChildrenByNameAsField;
property ChildrenByNameAsArrayEntry[AName: Int64]: TObject read GetChildrenByNameAsArrayEntry; property ChildrenByNameAsArrayEntry[AName: Int64; DerefCount: Integer]: TObject read GetChildrenByNameAsArrayEntry;
end; end;
TIdeTempWatchValue = class(TIdeWatchValue) TIdeTempWatchValue = class(TIdeWatchValue)
@ -604,8 +604,8 @@ type
FParentWatch: TIdeWatch; FParentWatch: TIdeWatch;
function GetChildWatch(ADispName, AnExpr: String): TIdeWatch; function GetChildWatch(ADispName, AnExpr: String): TIdeWatch;
function GetChildrenByNameAsArrayEntry(AName: Int64): TIdeWatch; function GetChildrenByNameAsArrayEntry(AName: Int64; DerefCount: Integer): TIdeWatch;
function GetChildrenByNameAsField(AName, AClassName: String): TIdeWatch; function GetChildrenByNameAsField(AName, AClassName: String; DerefCount: Integer): TIdeWatch;
function GetTopParentWatch: TIdeWatch; function GetTopParentWatch: TIdeWatch;
function GetValue(const AThreadId: Integer; const AStackFrame: Integer): TIdeWatchValue; function GetValue(const AThreadId: Integer; const AStackFrame: Integer): TIdeWatchValue;
function GetAnyValidParentWatchValue(AThreadId: Integer; AStackFrame: Integer): TIdeWatchValue; function GetAnyValidParentWatchValue(AThreadId: Integer; AStackFrame: Integer): TIdeWatchValue;
@ -636,8 +636,8 @@ type
procedure BeginChildUpdate; procedure BeginChildUpdate;
procedure EndChildUpdate; procedure EndChildUpdate;
procedure LimitChildWatchCount(AMaxCnt: Integer; AKeepIndexEntriesBelow: Int64 = low(Int64)); procedure LimitChildWatchCount(AMaxCnt: Integer; AKeepIndexEntriesBelow: Int64 = low(Int64));
property ChildrenByNameAsField[AName, AClassName: String]: TIdeWatch read GetChildrenByNameAsField; property ChildrenByNameAsField[AName, AClassName: String; DerefCount: Integer]: TIdeWatch read GetChildrenByNameAsField;
property ChildrenByNameAsArrayEntry[AName: Int64]: TIdeWatch read GetChildrenByNameAsArrayEntry; property ChildrenByNameAsArrayEntry[AName: Int64; DerefCount: Integer]: TIdeWatch read GetChildrenByNameAsArrayEntry;
function HasAllValidParents(AThreadId: Integer; AStackFrame: Integer): boolean; function HasAllValidParents(AThreadId: Integer; AStackFrame: Integer): boolean;
property ParentWatch: TIdeWatch read FParentWatch; property ParentWatch: TIdeWatch read FParentWatch;
property TopParentWatch: TIdeWatch read GetTopParentWatch; property TopParentWatch: TIdeWatch read GetTopParentWatch;
@ -949,8 +949,8 @@ type
function GetDisplayFormat: TWatchDisplayFormat; function GetDisplayFormat: TWatchDisplayFormat;
function GetTypeInfo: TDBGType; deprecated; function GetTypeInfo: TDBGType; deprecated;
function GetChildrenByNameAsArrayEntry(AName: Int64): TObject; function GetChildrenByNameAsArrayEntry(AName: Int64; DerefCount: Integer): TObject;
function GetChildrenByNameAsField(AName, AClassName: String): TObject; function GetChildrenByNameAsField(AName, AClassName: String; DerefCount: Integer): TObject;
protected protected
function FindParentValue: TIdeLocalsValue; virtual; function FindParentValue: TIdeLocalsValue; virtual;
@ -4378,7 +4378,8 @@ begin
Result := ddsEvaluating; // ddsWaitForParent; Result := ddsEvaluating; // ddsWaitForParent;
end; end;
function TIdeWatchValue.GetChildrenByNameAsArrayEntry(AName: Int64): TObject; function TIdeWatchValue.GetChildrenByNameAsArrayEntry(AName: Int64;
DerefCount: Integer): TObject;
begin begin
Result := nil; Result := nil;
if FWatch = nil then if FWatch = nil then
@ -4389,11 +4390,11 @@ begin
exit; exit;
end; end;
Result := Watch.ChildrenByNameAsArrayEntry[AName]; Result := Watch.ChildrenByNameAsArrayEntry[AName, DerefCount];
end; end;
function TIdeWatchValue.GetChildrenByNameAsField(AName, AClassName: String function TIdeWatchValue.GetChildrenByNameAsField(AName, AClassName: String;
): TObject; DerefCount: Integer): TObject;
begin begin
Result := nil; Result := nil;
if FWatch = nil then if FWatch = nil then
@ -4404,7 +4405,7 @@ begin
exit; exit;
end; end;
Result := Watch.ChildrenByNameAsField[AName, AClassName]; Result := Watch.ChildrenByNameAsField[AName, AClassName, DerefCount];
end; end;
function TIdeWatchValue.GetWatch: TIdeWatch; function TIdeWatchValue.GetWatch: TIdeWatch;
@ -6807,23 +6808,24 @@ begin
EndChildUpdate; EndChildUpdate;
end; end;
function TIdeWatch.GetChildrenByNameAsArrayEntry(AName: Int64): TIdeWatch; function TIdeWatch.GetChildrenByNameAsArrayEntry(AName: Int64;
DerefCount: Integer): TIdeWatch;
begin begin
Result := GetChildWatch(IntToStr(AName), Result := GetChildWatch(StringOfChar('^', DerefCount) + IntToStr(AName),
GetExpressionForArrayElement(Expression, AName) GetExpressionForArrayElement(Expression + StringOfChar('^', DerefCount), AName)
); );
end; end;
function TIdeWatch.GetChildrenByNameAsField(AName, AClassName: String function TIdeWatch.GetChildrenByNameAsField(AName, AClassName: String;
): TIdeWatch; DerefCount: Integer): TIdeWatch;
var var
Expr: String; Expr: String;
begin begin
Expr := Expression; Expr := Expression + StringOfChar('^', DerefCount);
if AClassName <> '' then if AClassName <> '' then
Expr := AClassName + '(' + Expr + ')'; Expr := AClassName + '(' + Expr + ')';
Expr := Expr + '.' + AName; Expr := Expr + '.' + AName;
Result := GetChildWatch(AName, Expr); Result := GetChildWatch(StringOfChar('^', DerefCount) + AName, Expr);
end; end;
function TIdeWatch.CreateChildWatches: TIdeWatches; function TIdeWatch.CreateChildWatches: TIdeWatches;
@ -7343,24 +7345,25 @@ begin
Result := nil; Result := nil;
end; end;
function TIdeLocalsValue.GetChildrenByNameAsArrayEntry(AName: Int64): TObject; function TIdeLocalsValue.GetChildrenByNameAsArrayEntry(AName: Int64;
DerefCount: Integer): TObject;
begin begin
Result := GetSubLocal(IntToStr(AName), Result := GetSubLocal(StringOfChar('^', DerefCount) + IntToStr(AName),
GetExpressionForArrayElement(Name, AName) GetExpressionForArrayElement(Name + StringOfChar('^', DerefCount), AName)
); );
end; end;
function TIdeLocalsValue.GetChildrenByNameAsField(AName, AClassName: String function TIdeLocalsValue.GetChildrenByNameAsField(AName, AClassName: String;
): TObject; DerefCount: Integer): TObject;
var var
Expr: String; Expr: String;
begin begin
Expr := Name; Expr := Name + StringOfChar('^', DerefCount);
// no defClassAutoCast for locals // if changed also update FindParentValue // no defClassAutoCast for locals // if changed also update FindParentValue
//if AClassName <> '' then //if AClassName <> '' then
// Expr := AClassName + '(' + Expr + ')'; // Expr := AClassName + '(' + Expr + ')';
Expr := Expr + '.' + AName; Expr := Expr + '.' + AName;
Result := GetSubLocal(AName, Expr); Result := GetSubLocal(StringOfChar('^', DerefCount) + AName, Expr);
end; end;
function TIdeLocalsValue.FindParentValue: TIdeLocalsValue; function TIdeLocalsValue.FindParentValue: TIdeLocalsValue;

View File

@ -34,8 +34,8 @@ type
end; end;
IWatchAbleResultIntf = interface ['wdr'] IWatchAbleResultIntf = interface ['wdr']
function GetChildrenByNameAsArrayEntry(AName: Int64): TObject; function GetChildrenByNameAsArrayEntry(AName: Int64; DerefCount: Integer): TObject;
function GetChildrenByNameAsField(AName, AClassName: String): TObject; function GetChildrenByNameAsField(AName, AClassName: String; DerefCount: Integer): TObject;
function GetEnabled: Boolean; function GetEnabled: Boolean;
function GetValidity: TDebuggerDataState; function GetValidity: TDebuggerDataState;
@ -44,8 +44,8 @@ type
function GetValue: string; function GetValue: string;
function GetResultData: TWatchResultData; function GetResultData: TWatchResultData;
property ChildrenByNameAsField[AName, AClassName: String]: TObject read GetChildrenByNameAsField; property ChildrenByNameAsField[AName, AClassName: String; DerefCount: Integer]: TObject read GetChildrenByNameAsField;
property ChildrenByNameAsArrayEntry[AName: Int64]: TObject read GetChildrenByNameAsArrayEntry; property ChildrenByNameAsArrayEntry[AName: Int64; DerefCount: Integer]: TObject read GetChildrenByNameAsArrayEntry;
property Enabled: Boolean read GetEnabled; property Enabled: Boolean read GetEnabled;
property Validity: TDebuggerDataState read GetValidity; property Validity: TDebuggerDataState read GetValidity;