FpDebug: improve dyn array detection

This commit is contained in:
Martin 2022-06-19 11:41:50 +02:00
parent 2835e63366
commit 77857b84ce
3 changed files with 46 additions and 11 deletions

View File

@ -5551,7 +5551,7 @@ begin
end;
function TFpSymbolDwarfTypeArray.GetFlags: TDbgSymbolFlags;
function IsDynSubRange(m: TFpSymbolDwarf): Boolean;
function IsDynSubRange(m: TFpSymbolDwarf; lb: Int64): Boolean;
begin
Result := sfSubRange in m.Flags;
if not Result then exit;
@ -5559,8 +5559,11 @@ function TFpSymbolDwarfTypeArray.GetFlags: TDbgSymbolFlags;
m := m.NestedTypeInfo;
Result := m <> nil;
if not Result then exit; // TODO: should not happen, handle error
Result := (TFpSymbolDwarfTypeSubRange(m).FHighBoundState = rfValue) // dynamic high bound // TODO:? Could be rfConst for locationExpr
or (TFpSymbolDwarfTypeSubRange(m).FHighBoundState = rfNotRead); // dynamic high bound (yet to be read)
// dynamic high bound (or yet to be read)
Result := (TFpSymbolDwarfTypeSubRange(m).FHighBoundState in [rfNotRead, rfValue, rfExpression]) and
( (TFpSymbolDwarfTypeSubRange(m).FLowBoundState = rfNotRead) or
(lb = 0)
);
end;
var
m: TFpSymbol;
@ -5571,7 +5574,7 @@ begin
m := NestedSymbol[0];
if (not m.GetValueBounds(nil, lb, hb)) or // e.g. Subrange with missing upper bound
(hb < lb) or
(IsDynSubRange(TFpSymbolDwarf(m)))
(IsDynSubRange(TFpSymbolDwarf(m), lb))
then
Result := Result + [sfDynArray]
else

View File

@ -341,7 +341,7 @@ begin
EntryRes := AnResData.CreateArrayValue(datUnknown, Cnt, LowBnd);
end
else
if (sfDynArray in ti.Flags) or (LowBnd = 0) then begin // LowBnd = 0 => there is some bug, reporting some dyn arrays as stat.
if (sfDynArray in ti.Flags) and (LowBnd = 0) then begin // LowBnd = 0 => there is some bug, reporting some dyn arrays as stat.
EntryRes := AnResData.CreateArrayValue(datDynArray, Cnt, 0);
if AnFpValue.FieldFlags * [svfInteger, svfCardinal] <> [] then
Addr := AnFpValue.AsCardinal

View File

@ -36,6 +36,7 @@ type
ehIgnPointerDerefData, // Ignore if a pointer has deref data or not
ehIgnKind, // Ignore skSimple, ....
ehIgnKindPtr, // Ignore skSimple, ONLY if got kind=skPointer
ehIgnKindArrayType, // Ignore dyn vs stat array
ehIgnTypeName, // Ignore the typename
ehIgnTypeNameInData, // Ignore any appearance of typename in data
ehMatchTypeName, // The typename is a regex
@ -88,6 +89,7 @@ type
function IgnData(ASymTypes: TSymbolTypes = []): TWatchExpectationResult;
function IgnKind(ASymTypes: TSymbolTypes = []): TWatchExpectationResult;
function IgnKindPtr(ASymTypes: TSymbolTypes = []): TWatchExpectationResult;
function IgnKindArrayType(ASymTypes: TSymbolTypes = []): TWatchExpectationResult;
function IgnTypeName(ASymTypes: TSymbolTypes = []): TWatchExpectationResult;
function MatchTypeName(ASymTypes: TSymbolTypes = []): TWatchExpectationResult;
@ -204,6 +206,7 @@ type
WatchTpInf: TDBGType; //deprecated;
Expectation: TWatchExpectationResult;
HasTypeInfo: Boolean;
IsNested: Boolean;
end;
{ TWatchExpectationList }
@ -242,7 +245,7 @@ type
function TestFalse(Name: string; Got: Boolean; AContext: TWatchExpTestCurrentData; AIgnoreReason: String): Boolean;
function CheckResult(AnWatchExp: TWatchExpectation): Boolean;
function CheckData(AContext: TWatchExpTestCurrentData; AnIgnoreRsn: String): Boolean; virtual;
function CheckData(AContext: TWatchExpTestCurrentData; AnIgnoreRsn: String; AnIsNested: Boolean = True): Boolean; virtual;
function VerifyDebuggerState: Boolean; virtual;
function VerifySymType(AContext: TWatchExpTestCurrentData; AnIgnoreRsn: String): Boolean; virtual;
function VerifyTypeName(AContext: TWatchExpTestCurrentData; AnIgnoreRsn: String): Boolean; virtual;
@ -892,6 +895,12 @@ begin
Result := Self.AddFlag(ehIgnKindPtr, ASymTypes);
end;
function TWatchExpectationResult.IgnKindArrayType(ASymTypes: TSymbolTypes
): TWatchExpectationResult;
begin
Result := Self.AddFlag(ehIgnKindArrayType, ASymTypes);
end;
function TWatchExpectationResult.IgnTypeName(ASymTypes: TSymbolTypes
): TWatchExpectationResult;
begin
@ -1421,7 +1430,7 @@ begin
if ehNotImplementedData in ehf then
AnIgnoreRsn := AnIgnoreRsn + 'Not implemented (Data)';
Result := CheckData(Context, AnIgnoreRsn);
Result := CheckData(Context, AnIgnoreRsn, False);
finally
FTest.TestBaseName := CurBaseName;
end;
@ -1429,8 +1438,9 @@ begin
end;
function TWatchExpectationList.CheckData(AContext: TWatchExpTestCurrentData;
AnIgnoreRsn: String): Boolean;
AnIgnoreRsn: String; AnIsNested: Boolean): Boolean;
begin
AContext.IsNested := AnIsNested;
case AContext.Expectation.ExpResultKind of
rkMatch: Result := CheckResultMatch(AContext, AnIgnoreRsn);
rkInteger: Result := CheckResultNum(AContext, False, AnIgnoreRsn);
@ -2008,10 +2018,25 @@ var
v, n: String;
parsed: array of String;
i, e: Integer;
ehf: TWatchExpErrorHandlingFlags;
PrePrint: Boolean;
begin
with AContext.WatchExp do begin
Result := True;
Expect := AContext.Expectation;
ehf := AContext.Expectation.ExpErrorHandlingFlags[Compiler.SymbolType];
PrePrint := AContext.WatchRes.ValueKind = rdkPrePrinted;
if (not (ehIgnKindArrayType in ehf)) and
(not (PrePrint and AContext.IsNested))
then begin
TestTrue('ValueKind is array', AContext.WatchRes.ValueKind = rdkArray, AContext, AnIgnoreRsn);
case AContext.Expectation.ExpResultKind of
rkStatArray: TestTrue('Is a static array', AContext.WatchRes.ArrayType = datStatArray, AContext, AnIgnoreRsn);
rkDynArray: TestTrue('Is a dynamic array', AContext.WatchRes.ArrayType = datDynArray, AContext, AnIgnoreRsn);
end;
end;
v := FWatchResultPrinter.PrintWatchValue(AContext.WatchRes, wdfDefault);
debugln([' expect ',Expect.ExpFullArrayLen,' got "',v,'"' ]);
@ -2039,12 +2064,19 @@ debugln([' expect ',Expect.ExpFullArrayLen,' got "',v,'"' ]);
SubContext := AContext;
for i := 0 to min(e, length(Expect.ExpSubResults)) - 1 do begin
FTest.TestBaseName := n + ' Idx='+IntToStr(i);
SubContext.WatchRes := TWatchResultDataPrePrinted.Create(parsed[i]);
AContext.WatchRes.SetSelectedIndex(i);
if PrePrint then
SubContext.WatchRes := TWatchResultDataPrePrinted.Create(parsed[i])
else
SubContext.WatchRes := AContext.WatchRes.SelectedEntry;
SubContext.Expectation := Expect.ExpSubResults[i];
Result := CheckData(SubContext, AnIgnoreRsn);
// if "not preprint" do treat this as non-nested
Result := CheckData(SubContext, AnIgnoreRsn, PrePrint);
FreeAndNil(SubContext.WatchRes);
if PrePrint then
FreeAndNil(SubContext.WatchRes);
end;
FTest.TestBaseName := n;
end;