LazDebuggerFp: new converter for variants (convert without function call)

This commit is contained in:
Martin 2023-03-12 09:29:21 +01:00
parent 9095837756
commit 06d582454b
10 changed files with 445 additions and 53 deletions

View File

@ -7,8 +7,9 @@ interface
uses
Classes, SysUtils, Forms, Controls, ExtCtrls, StdCtrls, ActnList,
FpDebugStringConstants, FpDebugValueConvertors, FpDebugDebuggerBase,
LazDebuggerValueConverter, LazDebuggerIntfBaseTypes, FpDbgInfo, FpDbgClasses,
FpdMemoryTools, FpDbgCallContextInfo, FpErrorMessages, DbgIntfBaseTypes;
LazDebuggerValueConverter, LazDebuggerIntfBaseTypes, LazDebuggerIntf,
FpDbgInfo, FpDbgClasses, FpdMemoryTools, FpDbgCallContextInfo,
FpErrorMessages, DbgIntfBaseTypes;
type
@ -52,7 +53,8 @@ type
procedure Assign(ASource: TFpDbgValueConverter); override;
function ConvertValue(ASourceValue: TFpValue;
AnFpDebugger: TFpDebugDebuggerBase;
AnExpressionScope: TFpDbgSymbolScope
AnExpressionScope: TFpDbgSymbolScope;
var AnResData: TLzDbgWatchDataIntf
): TFpValue; override;
published
@ -213,8 +215,8 @@ begin
end;
function TFpDbgValueConverterJsonForDebug.ConvertValue(ASourceValue: TFpValue;
AnFpDebugger: TFpDebugDebuggerBase; AnExpressionScope: TFpDbgSymbolScope
): TFpValue;
AnFpDebugger: TFpDebugDebuggerBase; AnExpressionScope: TFpDbgSymbolScope;
var AnResData: TLzDbgWatchDataIntf): TFpValue;
var
CurProccess: TDbgProcess;
TpName, JsonText: String;

View File

@ -0,0 +1,294 @@
unit FpDebugFpcConvVariantNormalizer;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FpDebugValueConvertors, FpDebugDebuggerBase,
FpDebugStringConstants, LazDebuggerValueConverter, LazDebuggerIntf, FpDbgInfo,
FpDbgUtil, FpErrorMessages, FpDbgDwarf, FpdMemoryTools, DbgIntfBaseTypes;
type
(**** Display variant as single/simple value ****)
{ TFpDbgValueConverterVariantNormalizer }
TFpDbgValueConverterVariantNormalizer = class(TFpDbgValueConverter)
protected
//function GetSettingsFrame: TLazDbgValueConverterSettingsFrameIntf; override; // TConverterSettingsFrameBase
public
class function GetName: String; override;
function GetRegistryEntry: TLazDbgValueConvertRegistryEntryClass; override;
function NeedConversionLimit: Boolean; override;
function CanHandleValue(ASourceValue: TFpValue; AnFpDebugger: TFpDebugDebuggerBase): Boolean; override;
function ConvertValue(ASourceValue: TFpValue;
AnFpDebugger: TFpDebugDebuggerBase;
AnExpressionScope: TFpDbgSymbolScope;
var AnResData: TLzDbgWatchDataIntf
): TFpValue; override;
end;
{ TFpDbgValueConverterVariantNormalizerRegistryEntry }
TFpDbgValueConverterVariantNormalizerRegistryEntry = class(TFpDbgValueConverterRegistryEntry)
public
class function GetConvertorClass: TClass; override;
end;
implementation
{ TFpDbgValueConverterVariantNormalizer }
class function TFpDbgValueConverterVariantNormalizer.GetName: String;
begin
Result := drsConverterNormalizeVariant;
end;
function TFpDbgValueConverterVariantNormalizer.GetRegistryEntry: TLazDbgValueConvertRegistryEntryClass;
begin
Result := TFpDbgValueConverterVariantNormalizerRegistryEntry;
end;
function TFpDbgValueConverterVariantNormalizer.NeedConversionLimit: Boolean;
begin
Result := False;
end;
function TFpDbgValueConverterVariantNormalizer.CanHandleValue(
ASourceValue: TFpValue; AnFpDebugger: TFpDebugDebuggerBase): Boolean;
var
m, m2: TFpValue;
begin
Result := (ASourceValue.Kind = skRecord) and (AnFpDebugger.DbgController.CurrentProcess <> nil);
if (not Result) then
exit;
if AnFpDebugger.DbgController.CurrentProcess.Mode = dm32 then
Result := (ASourceValue.DataSize.Size = 16)
else
Result := (ASourceValue.DataSize.Size = 24);
if (not Result) then
exit;
if (ASourceValue.MemberCount = 1) then begin
m := ASourceValue.Member[0];
Result := (m <> nil);
if not Result then begin
exit;
m.ReleaseReference;
end;
m2 := m.Member[-1];
m.ReleaseReference;
Result := (m2 <> nil) and (m2.FieldFlags * [svfInteger, svfCardinal, svfOrdinal] <> []);
m2.ReleaseReference;
exit;
end
else
begin
m := ASourceValue.MemberByName['vtype'];
Result := (m <> nil);
m.ReleaseReference;
exit;
end;
Result := False;
end;
function TFpDbgValueConverterVariantNormalizer.ConvertValue(
ASourceValue: TFpValue; AnFpDebugger: TFpDebugDebuggerBase;
AnExpressionScope: TFpDbgSymbolScope; var AnResData: TLzDbgWatchDataIntf
): TFpValue;
procedure ReturnSourceValue;
begin
Result.ReleaseReference;
ASourceValue.AddReference;
Result := ASourceValue;
end;
procedure ReturnNil;
begin
Result.ReleaseReference;
Result := nil;
end;
procedure HandleAnsiString;
var
Addr: TFpDbgMemLocation;
sz: Integer;
SLen: Int64;
Str: string;
begin
if (Result = nil) then begin
ReturnSourceValue;
exit;
end;
if (Result.Kind <> skPointer) then
exit;
Addr := Result.DerefAddress;
if not IsTargetNotNil(Addr) then
exit;
sz := AnExpressionScope.LocationContext.SizeOfAddress;
Addr.Address := Addr.Address - sz;
AnExpressionScope.LocationContext.ReadSignedInt(Addr, SizeVal(sz), SLen);
if IsError(AnExpressionScope.LocationContext.LastMemError) then begin
AnResData.CreateError('<Error reading string>');
ReturnNil;
exit;
end;
Addr.Address := Addr.Address + sz;
if SLen > AnExpressionScope.LocationContext.MemManager.MemLimits.MaxStringLen then
SLen := AnExpressionScope.LocationContext.MemManager.MemLimits.MaxStringLen;
SetLength(Str, SLen);
if SLen > 0 then
AnExpressionScope.LocationContext.ReadMemory(Addr, SizeVal(SLen), @Str[1]);
if IsError(AnExpressionScope.LocationContext.LastMemError) then
AnResData.CreateError('<Error reading string>')
else
AnResData.CreateString(Str);
ReturnNil;
end;
var
m, m2, vtype: TFpValue;
discr, i: Int64;
t: TFpSymbol;
OldResData: TLzDbgWatchDataIntf;
begin
Result := nil;
OldResData := AnResData;
AnResData := AnResData.CreateVariantValue();
t := ASourceValue.TypeInfo;
if (t <> nil) then
OldResData.SetTypeName(t.Name);
if ASourceValue.MemberCount = 1 then begin
// dwarf 3
m := ASourceValue.Member[0];
if m = nil then begin
ReturnSourceValue;
exit;
end;
vtype := m.Member[-1];
if vtype = nil then begin
m.ReleaseReference;
ReturnSourceValue;
exit;
end;
discr := vtype.AsInteger;
try
for i := 0 to m.MemberCount do begin
m2 := m.Member[i];
try
if (m2 <> nil) and
(m2.DbgSymbol is TFpSymbolDwarfTypeVariant) and
(TFpSymbolDwarfTypeVariant(m2.DbgSymbol).MatchesDiscr(discr)) and
(m2.MemberCount = 1)
then begin
Result := m2.Member[0];
case discr of
0: if Result = nil then AnResData.CreatePrePrinted('<Empty>');
1: if Result = nil then AnResData.CreatePrePrinted('<Null>');
256: HandleAnsiString;
otherwise
if Result = nil then ReturnSourceValue;
end;
exit;
end;
finally
m2.ReleaseReference;
end;
end;
finally
m.ReleaseReference;
vtype.ReleaseReference;
end;
end
else begin
// dwarf 2
vtype := ASourceValue.MemberByName['vtype'];
try
i := vtype.AsInteger;
case i of
0: AnResData.CreatePrePrinted('<Empty>');
1: AnResData.CreatePrePrinted('<Null>');
2: Result := ASourceValue.MemberByName['VSMALLINT'];
3: Result := ASourceValue.MemberByName['VINTEGER'];
4: Result := ASourceValue.MemberByName['VSINGLE'];
5: Result := ASourceValue.MemberByName['VDOUBLE'];
6: Result := ASourceValue.MemberByName['VCURRENCY'];
7: Result := ASourceValue.MemberByName['VDATE'];
8: Result := ASourceValue.MemberByName['VOLESTR'];
9: Result := ASourceValue.MemberByName['VDISPATCH'];
10: Result := ASourceValue.MemberByName['VERROR'];
11: Result := ASourceValue.MemberByName['VBOOLEAN'];
//12: varVariant
13: Result := ASourceValue.MemberByName['VUNKNOWN'];
//14: varDecimal
//15??
16: Result := ASourceValue.MemberByName['VSHORTINT'];
17: Result := ASourceValue.MemberByName['VBYTE'];
18: Result := ASourceValue.MemberByName['VWORD'];
19: Result := ASourceValue.MemberByName['VLONGWORD'];
20: Result := ASourceValue.MemberByName['VINT64'];
21: Result := ASourceValue.MemberByName['VQWORD'];
22: Result := ASourceValue.MemberByName['VWORD'];
//
36: Result := ASourceValue.MemberByName['VRECORD'];
//72
256: Result := ASourceValue.MemberByName['VSTRING'];
257: Result := ASourceValue.MemberByName['VANY'];
258: Result := ASourceValue.MemberByName['VUSTRING'];
//258: varUString
8192: Result := ASourceValue.MemberByName['VARRAY'];
16384: Result := ASourceValue.MemberByName['VPOINTER'];
end;
if Result = nil then begin
ReturnSourceValue;
end
else
case i of
256: begin
HandleAnsiString;
exit;
end;
end;
finally
vtype.ReleaseReference;
end;
exit;
end;
if Result = nil then
ReturnSourceValue;
end;
{ TFpDbgValueConverterVariantNormalizerRegistryEntry }
class function TFpDbgValueConverterVariantNormalizerRegistryEntry.GetConvertorClass: TClass;
begin
Result := TFpDbgValueConverterVariantNormalizer;
end;
initialization
ValueConverterRegistry.Add(TFpDbgValueConverterVariantNormalizerRegistryEntry);
end.

View File

@ -109,7 +109,7 @@ function TFpLazDbgWatchResultConvertor.DoValueToResData(AnFpValue: TFpValue;
var
NewFpVal: TFpValue;
CurConv: TFpDbgValueConverter;
AnResFld: TLzDbgWatchDataIntf;
AnResFld, AnResFld2: TLzDbgWatchDataIntf;
WasInArray, WasInNonConvert: Boolean;
begin
Result := False;
@ -153,35 +153,43 @@ begin
CurConv := GetValConv(AnFpValue, RecurseCnt <> RecurseCntLow);
end;
if (CurConv <> nil) then begin
if (CurConv <> nil) and CurConv.CanHandleValue(AnFpValue, Debugger) then begin
AnResFld := AnResData.CreateValueHandlerResult(CurConv);
if (FMaxTotalConv <= 0) then
ReleaseRefAndNil(CurConv)
else
if CurConv.NeedConversionLimit then
dec(FMaxTotalConv);
if FInArray then begin
if (FCurMaxArrayConv <= 0) then
ReleaseRefAndNil(CurConv)
else
if CurConv.NeedConversionLimit then
dec(FCurMaxArrayConv);
end;
if (CurConv <> nil) then begin
FInNonConvert := True;
NewFpVal := CurConv.ConvertValue(AnFpValue, Debugger, ExpressionScope);
if NewFpVal <> nil then begin
Result := inherited DoValueToResData(NewFpVal, AnResFld);
AnResFld2 := AnResFld;
NewFpVal := CurConv.ConvertValue(AnFpValue, Debugger, ExpressionScope, AnResFld2);
if AnResFld2 = AnResFld then begin
if NewFpVal <> nil then begin
Result := inherited DoValueToResData(NewFpVal, AnResFld);
end
else begin
if IsError(CurConv.LastErrror) then
AnResFld.CreateError(ErrorHandler.ErrorAsString(CurConv.LastErrror))
else
AnResFld.CreateError('Conversion failed');
Result := True;
end;
end
else begin
if IsError(CurConv.LastErrror) then
AnResFld.CreateError(ErrorHandler.ErrorAsString(CurConv.LastErrror))
else
AnResFld.CreateError('Conversion failed');
Result := True;
end;
else
if (AnResFld2 <> nil) and (NewFpVal <> nil) then
Result := inherited DoValueToResData(NewFpVal, AnResFld2);
end
else
AnResFld.CreateError('');

View File

@ -14,6 +14,7 @@ resourcestring
drsFunctionName = 'Function name';
drsCallSysVarToLStr = 'Call SysVarToLStr';
drsCallJsonForDebug = 'Call JsonForDebug';
drsConverterNormalizeVariant = 'Convert variant to value type';
drsRunAllThreadsWhileEval = 'Run all threads while evaluating';
implementation

View File

@ -9,7 +9,8 @@ uses
Classes, SysUtils, FpDbgInfo, FpdMemoryTools, FpDbgCallContextInfo,
FpPascalBuilder, FpErrorMessages, FpDbgClasses, FpDbgUtil, DbgIntfBaseTypes,
LazClasses, LCLProc, Forms, StdCtrls, Controls, StrUtils, FpDebugDebuggerBase,
FpDebugStringConstants, LazDebuggerValueConverter, LazDebuggerIntfBaseTypes;
FpDebugStringConstants, LazDebuggerValueConverter, LazDebuggerIntfBaseTypes,
LazDebuggerIntf;
type
(* TFpDbgValueConverter and descendants
@ -32,25 +33,55 @@ type
constructor Create; virtual;
procedure Assign(ASource: TFpDbgValueConverter); virtual;
function CreateCopy: TLazDbgValueConverterIntf; virtual;
function NeedConversionLimit: Boolean; virtual;
(* CanHandleValue must return the SAME RESULT if called repeatedly (e.g. in an array)
CanHandleValue must NOT depend on DATA, or anything that can change
CanHandleValue must ONLY check type info (or other data that will not change)
- For any other/uncertain case the converter should create an error (empty text) in
ConvertValue, changing AnResData
*)
function CanHandleValue(ASourceValue: TFpValue; AnFpDebugger: TFpDebugDebuggerBase): Boolean; virtual;
(* ConvertValue
* AnResData = nil
=> Do nothing => ConvertValue must have done AnResData.Create....
* Result <> nil / AnResData <> nil
=> Use Result (instead of ASourceValue) to build watch-data
=> use the new AnResData (in case it changed)
If the new AnResData = nil, then do nothing
* Result = nil
- AnResData NOT-changed
=> Create an error (IDE will show ASourceValue)
- AnResData CHANGED
=> Do nothing => ConvertValue must have done AnResData.Create....
*)
function ConvertValue(ASourceValue: TFpValue;
AnFpDebugger: TFpDebugDebuggerBase;
AnExpressionScope: TFpDbgSymbolScope
AnExpressionScope: TFpDbgSymbolScope;
var AnResData: TLzDbgWatchDataIntf // if changed, then the converter has done its job, and should return nil
): TFpValue; virtual; abstract;
procedure SetError(AnError: TFpError);
property LastErrror: TFpError read FLastErrror;
end;
TFpDbgValueConverterClass = class of TFpDbgValueConverter;
{ TConverterSettingsFrameBase }
TConverterSettingsFrameBase = class(TFrame, TLazDbgValueConverterSettingsFrameIntf)
protected
function GetFrame: TObject; virtual;
public
procedure ReadFrom(AConvertor: TLazDbgValueConverterIntf); virtual;
function WriteTo(AConvertor: TLazDbgValueConverterIntf): Boolean; virtual;
end;
{ TConverterWithFuncCallSettingsFrame }
TConverterWithFuncCallSettingsFrame = class(TFrame, TLazDbgValueConverterSettingsFrameIntf)
TConverterWithFuncCallSettingsFrame = class(TConverterSettingsFrameBase)
chkRunAll: TCheckBox;
protected
function GetFrame: TObject;
public
constructor Create(TheOwner: TComponent); override;
procedure ReadFrom(AConvertor: TLazDbgValueConverterIntf);
function WriteTo(AConvertor: TLazDbgValueConverterIntf): Boolean;
procedure ReadFrom(AConvertor: TLazDbgValueConverterIntf); override;
function WriteTo(AConvertor: TLazDbgValueConverterIntf): Boolean; override;
end;
{ TFpDbgValueConverterWithFuncCall }
@ -81,6 +112,7 @@ type
class function GetDebuggerClass: TClass; override;
end;
(**** Call SysVarToLStr on variant ****)
{ TFpDbgValueConverterVariantToLStr }
@ -94,7 +126,8 @@ type
function GetRegistryEntry: TLazDbgValueConvertRegistryEntryClass; override;
function ConvertValue(ASourceValue: TFpValue;
AnFpDebugger: TFpDebugDebuggerBase;
AnExpressionScope: TFpDbgSymbolScope
AnExpressionScope: TFpDbgSymbolScope;
var AnResData: TLzDbgWatchDataIntf
): TFpValue; override;
end;
@ -130,6 +163,17 @@ begin
Result := c;
end;
function TFpDbgValueConverter.NeedConversionLimit: Boolean;
begin
Result := True;
end;
function TFpDbgValueConverter.CanHandleValue(ASourceValue: TFpValue;
AnFpDebugger: TFpDebugDebuggerBase): Boolean;
begin
Result := True;
end;
procedure TFpDbgValueConverter.SetError(AnError: TFpError);
begin
FLastErrror := AnError;
@ -166,6 +210,25 @@ begin
//
end;
{ TConverterSettingsFrameBase }
function TConverterSettingsFrameBase.GetFrame: TObject;
begin
Result := Self;
end;
procedure TConverterSettingsFrameBase.ReadFrom(
AConvertor: TLazDbgValueConverterIntf);
begin
//
end;
function TConverterSettingsFrameBase.WriteTo(
AConvertor: TLazDbgValueConverterIntf): Boolean;
begin
Result := False; // nothing changed
end;
{ TConverterWithFuncCallSettingsFrame }
procedure TConverterWithFuncCallSettingsFrame.ReadFrom(
@ -197,11 +260,6 @@ begin
c.FuncCallRunAllThreads := chkRunAll.Checked;
end;
function TConverterWithFuncCallSettingsFrame.GetFrame: TObject;
begin
Result := Self;
end;
constructor TConverterWithFuncCallSettingsFrame.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
@ -424,8 +482,8 @@ begin
end;
function TFpDbgValueConverterVariantToLStr.ConvertValue(ASourceValue: TFpValue;
AnFpDebugger: TFpDebugDebuggerBase; AnExpressionScope: TFpDbgSymbolScope
): TFpValue;
AnFpDebugger: TFpDebugDebuggerBase; AnExpressionScope: TFpDbgSymbolScope;
var AnResData: TLzDbgWatchDataIntf): TFpValue;
var
NewResult, ProcVal, m: TFpValue;
ProcSym: TFpSymbol;

View File

@ -56,6 +56,10 @@
<Filename Value="fpdebugstringconstants.pas"/>
<UnitName Value="FpDebugStringConstants"/>
</Item>
<Item>
<Filename Value="fpdebugfpcconvvariantnormalizer.pas"/>
<UnitName Value="FpDebugFpcConvVariantNormalizer"/>
</Item>
</Files>
<RequiredPkgs>
<Item>

View File

@ -10,7 +10,8 @@ interface
uses
FpDebugDebugger, FpDebugDebuggerUtils, FpDebugDebuggerWorkThreads,
FpDebugValueConvertors, FpDebugDebuggerBase, FpDebuggerResultData,
FpDebugConvDebugForJson, FpDebugStringConstants, LazarusPackageIntf;
FpDebugConvDebugForJson, FpDebugStringConstants,
FpDebugFpcConvVariantNormalizer, LazarusPackageIntf;
implementation

View File

@ -454,6 +454,7 @@ begin
rdkProcedure,
rdkFunctionRef,
rdkProcedureRef: Result := PrintProc(AResValue, ADispFormat, ANestLvl);
rdkVariant: Result := PrintWatchValueEx(AResValue.DerefData, ADispFormat, ANestLvl);
end;
end;

View File

@ -751,6 +751,7 @@ type
function GetDirectFieldCount: Integer; virtual; abstract;
function GetFieldCount: Integer; virtual; abstract;
function GetFields(AnIndex: Integer): TWatchResultDataFieldInfo; virtual; abstract;
function GetConvertedRes: TWatchResultData; virtual;
function GetFieldVisibility: TLzDbgFieldVisibility; virtual; abstract;
@ -817,6 +818,8 @@ type
property DirectFieldCount: Integer read GetDirectFieldCount; // without inherited fields
property Fields[AnIndex: Integer]: TWatchResultDataFieldInfo read GetFields;
property ConvertedRes: TWatchResultData read GetConvertedRes;
// variant
property FieldVisibility: TLzDbgFieldVisibility read GetFieldVisibility;
end;
@ -1447,6 +1450,7 @@ type
function GetClassID: TWatchResultDataClassID; override;
protected
function GetBackendValueHandler: TLazDbgValueConverterIntf; override;
function GetConvertedRes: TWatchResultData; override;
public
constructor Create(AHandler: TLazDbgValueConverterIntf);
end;
@ -2586,6 +2590,11 @@ begin
Result := wdPrePrint;
end;
function TWatchResultData.GetConvertedRes: TWatchResultData;
begin
Result := Self;
end;
function TWatchResultData.GetTypeName: String;
begin
Result := FTypeName;
@ -4703,6 +4712,19 @@ begin
Result := FType.FHandler;
end;
function TWatchResultDataConverted.GetConvertedRes: TWatchResultData;
begin
if (FieldCount > 0) then
Result := Fields[0].Field;
if (FieldCount > 1) and
( (Fields[0].Field = nil) or
(Fields[0].Field.ValueKind = rdkError)
)
then
Result := Fields[1].Field;
end;
constructor TWatchResultDataConverted.Create(
AHandler: TLazDbgValueConverterIntf);
begin

View File

@ -85,6 +85,7 @@ type
FUpdatedData: Boolean;
FWatchPrinter: TWatchResultPrinter;
FCurrentResData: TWatchResultData;
FCurrentTypePrefix: AnsiString;
FHumanReadable: ansistring;
FGridData: TStringGrid;
FGridMethods: TStringGrid;
@ -199,11 +200,11 @@ begin
WatchInspectNav1.ColVisibilityEnabled := False;
v := ClearMultiline(FWatchPrinter.PrintWatchValue(Res, wdfDefault));
StatusBar1.SimpleText:=ShortenedExpression+' : '+Res.TypeName + ' = ' + v;
StatusBar1.SimpleText:=ShortenedExpression+' : '+FCurrentTypePrefix+Res.TypeName + ' = ' + v;
GridDataSetup;
FGridData.Cells[1,1]:=WatchInspectNav1.Expression;
FGridData.Cells[2,1]:=Res.TypeName;
FGridData.Cells[2,1]:=FCurrentTypePrefix+Res.TypeName;
FGridData.Cells[3,1]:=v;
end;
@ -225,12 +226,12 @@ begin
WatchInspectNav1.ColVisibilityEnabled := False;
v := ClearMultiline(FWatchPrinter.PrintWatchValue(Res, wdfDefault));
StatusBar1.SimpleText:=ShortenedExpression+' : '+Res.TypeName + ' = ' + v;
StatusBar1.SimpleText:=ShortenedExpression+' : '+FCurrentTypePrefix+Res.TypeName + ' = ' + v;
GridDataSetup;
v := ClearMultiline(FWatchPrinter.PrintWatchValue(Res, wdfPointer));
FGridData.Cells[1,1]:=WatchInspectNav1.Expression;
FGridData.Cells[2,1]:=Res.TypeName;
FGridData.Cells[2,1]:=FCurrentTypePrefix+Res.TypeName;
FGridData.Cells[3,1]:=v;
Res := Res.DerefData;
@ -261,11 +262,11 @@ begin
WatchInspectNav1.ColVisibilityEnabled := False;
v := ClearMultiline(FWatchPrinter.PrintWatchValue(Res, wdfDefault));
StatusBar1.SimpleText:=ShortenedExpression+' : '+Res.TypeName + ' = ' + v;
StatusBar1.SimpleText:=ShortenedExpression+' : '+FCurrentTypePrefix+Res.TypeName + ' = ' + v;
GridDataSetup;
FGridData.Cells[1,1]:=WatchInspectNav1.Expression;
FGridData.Cells[2,1]:=Res.TypeName;
FGridData.Cells[2,1]:=FCurrentTypePrefix+Res.TypeName;
// TODO: show declaration (all elements)
FGridData.Cells[3,1]:=v;
end;
@ -301,7 +302,7 @@ begin
exit;
end;
StatusBar1.SimpleText:=ShortenedExpression+': '+Res.TypeName + ' Len: ' + IntToStr(Res.ArrayLength);
StatusBar1.SimpleText:=ShortenedExpression+': '+FCurrentTypePrefix+Res.TypeName + ' Len: ' + IntToStr(Res.ArrayLength);
LowBnd := Res.LowBound;
if FUpdatedData then begin
@ -341,6 +342,7 @@ begin
for i := SubStart to SubStart+CurPageCount-1 do begin
Res.SetSelectedIndex(i);
Entry := Res.SelectedEntry;
Entry := Entry.ConvertedRes;
FGridData.Cells[1,i+1-SubStart] := IntToStr(LowBnd + ResIdxOffs + i);
FGridData.Cells[2,i+1-SubStart] := Entry.TypeName;
FGridData.Cells[3,i+1-SubStart] := ClearMultiline(FWatchPrinter.PrintWatchValue(Entry, wdfDefault));
@ -371,9 +373,9 @@ begin
if Res.Anchestor <> nil then
AnchType := Res.Anchestor.TypeName;
if (Res.ValueKind = rdkStruct) and (AnchType <> '') then
StatusBar1.SimpleText:=Format(lisInspectClassInherit, [ShortenedExpression, Res.TypeName, AnchType])
StatusBar1.SimpleText:=Format(lisInspectClassInherit, [ShortenedExpression, FCurrentTypePrefix+Res.TypeName, AnchType])
else
StatusBar1.SimpleText:=ShortenedExpression+' : '+Res.TypeName + ' = ' + FHumanReadable;
StatusBar1.SimpleText:=ShortenedExpression+' : '+FCurrentTypePrefix+Res.TypeName + ' = ' + FHumanReadable;
GridDataSetup;
FldCnt := 0;
@ -407,6 +409,7 @@ begin
m := 1;
for FldInfo in res do begin
Fld := FldInfo.Field;
Fld := Fld.ConvertedRes;
Fld2 := ExtractProcResFromMethod(Fld);
if (MethCnt > 0) and
(Fld <> nil) and
@ -1198,6 +1201,7 @@ begin
FAlternateExpression := '';
FExpressionWasEvaluated := True;
FCurrentResData := WatchInspectNav1.CurrentWatchValue.ResultData;
FCurrentTypePrefix := '';
FHumanReadable := FWatchPrinter.PrintWatchValue(FCurrentResData, wdfStructure);
if WatchInspectNav1.CurrentWatchValue.Validity = ddsValid then begin
@ -1229,18 +1233,15 @@ begin
else begin
// resultdata
if (FCurrentResData.ValueKind = rdkConvertRes)
then begin
if (FCurrentResData.FieldCount > 0) then
//if (FCurrentResData.FieldCount = 1) then
FCurrentResData := FCurrentResData.Fields[0].Field;
while (FCurrentResData.ValueKind = rdkConvertRes) or (FCurrentResData.ValueKind = rdkVariant) do
begin
FCurrentResData := FCurrentResData.ConvertedRes;
if (FCurrentResData.FieldCount > 1) and
( (FCurrentResData.Fields[0].Field = nil) or
(FCurrentResData.Fields[0].Field.ValueKind = rdkError)
)
then
FCurrentResData := FCurrentResData.Fields[1].Field;
if FCurrentResData.ValueKind = rdkVariant then begin
if FCurrentResData.TypeName <> '' then
FCurrentTypePrefix := FCurrentResData.TypeName+ ': ';
FCurrentResData := FCurrentResData.DerefData;
end;
end;