1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
|
unit FpDebuggerResultData;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FpWatchResultData, FpDbgInfo, FpdMemoryTools,
FpErrorMessages, DbgIntfBaseTypes, LazClasses, FpDebugValueConvertors,
FpDebugDebuggerBase, LazDebuggerIntf, LazDebuggerValueConverter;
type
{ TFpLazDbgWatchResultConvertor }
TFpLazDbgWatchResultConvertor = class(TFpWatchResultConvertor)
private
FDebugger: TFpDebugDebuggerBase;
FExpressionScope: TFpDbgSymbolScope;
FValConvList: ILazDbgValueConvertSelectorListIntf;
FValConfig: ILazDbgValueConvertSelectorIntf;
FExtraDephtLevelIsArray: Boolean; // defExtraDepth / RecurseCnt=-1
FExtraDephtLevelItemConv: TFpDbgValueConverter;
FLevelZeroKind: TDbgSymbolKind;
FLevelZeroArrayConv: TFpDbgValueConverter; // All itens in array have same type / optimize and keep converter
FInArray, FInNonConvert: Boolean;
FMaxTotalConv, FMaxArrayConv, FCurMaxArrayConv: Integer;
FNoConvert: Boolean;
function GetValConv(AnFpValue: TFpValue; IgnoreInstanceClass: boolean = False): TFpDbgValueConverter; inline;
procedure SetMaxArrayConv(AValue: Integer);
procedure SetMaxTotalConv(AValue: Integer);
public
destructor Destroy; override;
function DoValueToResData(AnFpValue: TFpValue;
AnResData: IDbgWatchDataIntf): Boolean; override;
property ValConvList: ILazDbgValueConvertSelectorListIntf read FValConvList write FValConvList;
property ValConfig: ILazDbgValueConvertSelectorIntf read FValConfig write FValConfig;
property Debugger: TFpDebugDebuggerBase read FDebugger write FDebugger;
property ExpressionScope: TFpDbgSymbolScope read FExpressionScope write FExpressionScope;
property MaxArrayConv: Integer read FMaxArrayConv write SetMaxArrayConv;
property MaxTotalConv: Integer read FMaxTotalConv write SetMaxTotalConv;
end;
implementation
{ TFpLazDbgWatchResultConvertor }
function TFpLazDbgWatchResultConvertor.GetValConv(AnFpValue: TFpValue;
IgnoreInstanceClass: boolean): TFpDbgValueConverter;
var
i, c: Integer;
begin
Result := nil;
if (FNoConvert) or
(FInArray and (FMaxArrayConv <= 0))
then
exit;
if (ValConfig <> nil) then begin
if ValConfig.CheckMatch(AnFpValue, IgnoreInstanceClass) then
Result := ValConfig.GetConverter.GetObject as TFpDbgValueConverter;
if Result <> nil then
Result.AddReference;
end
else
if (ValConvList <> nil) then begin
ValConvList.Lock;
try
i := 0;
c := ValConvList.Count;
while (i < c) and (not ValConvList[i].CheckMatch(AnFpValue, IgnoreInstanceClass)) do
inc(i);
if i < c then
Result := ValConvList[i].GetConverter.GetObject as TFpDbgValueConverter;
if Result <> nil then
Result.AddReference;
finally
ValConvList.Unlock;
end;
end;
end;
procedure TFpLazDbgWatchResultConvertor.SetMaxArrayConv(AValue: Integer);
begin
if FMaxArrayConv = AValue then Exit;
FMaxArrayConv := AValue;
FCurMaxArrayConv := AValue;
end;
procedure TFpLazDbgWatchResultConvertor.SetMaxTotalConv(AValue: Integer);
begin
if FMaxTotalConv = AValue then Exit;
FMaxTotalConv := AValue;
FNoConvert := FMaxTotalConv <= 0;
end;
destructor TFpLazDbgWatchResultConvertor.Destroy;
begin
inherited Destroy;
FExtraDephtLevelItemConv.ReleaseReference;
FLevelZeroArrayConv.ReleaseReference;
end;
function TFpLazDbgWatchResultConvertor.DoValueToResData(AnFpValue: TFpValue;
AnResData: IDbgWatchDataIntf): Boolean;
var
NewFpVal: TFpValue;
CurConv: TFpDbgValueConverter;
AnResFld, AnResFld2: IDbgWatchDataIntf;
WasInArray, WasInNonConvert: Boolean;
begin
Result := False;
if (RecurseCnt = -1) and (AnFpValue.Kind in [skArray]) then
FExtraDephtLevelIsArray := True;
if RecurseCnt = 0 then begin
FLevelZeroKind := AnFpValue.Kind;
FCurMaxArrayConv := FMaxArrayConv;
if not FExtraDephtLevelIsArray then
ReleaseRefAndNil(FLevelZeroArrayConv);
end;
WasInArray := FInArray;
WasInNonConvert := FInNonConvert;
if (RecurseCnt >= 0) and (AnFpValue.Kind in [skArray]) then
FInArray := True;
if not FInNonConvert then begin
CurConv := nil;
NewFpVal := nil;
try
if (RecurseCnt = 0) and (FExtraDephtLevelIsArray) then begin
if FExtraDephtLevelItemConv = nil then
FExtraDephtLevelItemConv := GetValConv(AnFpValue, RecurseCnt <> RecurseCntLow);
CurConv := FExtraDephtLevelItemConv;
if CurConv <> nil then
CurConv.AddReference;
end
else
if (RecurseCnt = 1) and (FLevelZeroKind = skArray) then begin
if FLevelZeroArrayConv = nil then
FLevelZeroArrayConv := GetValConv(AnFpValue, RecurseCnt <> RecurseCntLow);
CurConv := FLevelZeroArrayConv;
if CurConv <> nil then
CurConv.AddReference;
end
else begin
CurConv := GetValConv(AnFpValue, RecurseCnt <> RecurseCntLow);
end;
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;
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
if (AnResFld2 <> nil) and (NewFpVal <> nil) then
Result := inherited DoValueToResData(NewFpVal, AnResFld2);
end
else
AnResFld.CreateError('');
AnResData := AnResData.SetDerefData;
end;
finally
CurConv.ReleaseReference;
NewFpVal.ReleaseReference;
end;
end;
if inherited DoValueToResData(AnFpValue, AnResData) then
Result := True;
FInArray := WasInArray;
FInNonConvert := WasInNonConvert;
end;
end.
|