mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-12-08 01:17:29 +01:00
LazDebuggerFp: new converter for variants (convert without function call)
This commit is contained in:
parent
9095837756
commit
06d582454b
@ -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;
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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('');
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -56,6 +56,10 @@
|
||||
<Filename Value="fpdebugstringconstants.pas"/>
|
||||
<UnitName Value="FpDebugStringConstants"/>
|
||||
</Item>
|
||||
<Item>
|
||||
<Filename Value="fpdebugfpcconvvariantnormalizer.pas"/>
|
||||
<UnitName Value="FpDebugFpcConvVariantNormalizer"/>
|
||||
</Item>
|
||||
</Files>
|
||||
<RequiredPkgs>
|
||||
<Item>
|
||||
|
||||
@ -10,7 +10,8 @@ interface
|
||||
uses
|
||||
FpDebugDebugger, FpDebugDebuggerUtils, FpDebugDebuggerWorkThreads,
|
||||
FpDebugValueConvertors, FpDebugDebuggerBase, FpDebuggerResultData,
|
||||
FpDebugConvDebugForJson, FpDebugStringConstants, LazarusPackageIntf;
|
||||
FpDebugConvDebugForJson, FpDebugStringConstants,
|
||||
FpDebugFpcConvVariantNormalizer, LazarusPackageIntf;
|
||||
|
||||
implementation
|
||||
|
||||
|
||||
@ -454,6 +454,7 @@ begin
|
||||
rdkProcedure,
|
||||
rdkFunctionRef,
|
||||
rdkProcedureRef: Result := PrintProc(AResValue, ADispFormat, ANestLvl);
|
||||
rdkVariant: Result := PrintWatchValueEx(AResValue.DerefData, ADispFormat, ANestLvl);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user