FpDebug: Add comparing enum-values in watches "enum1 >= enum2"

(cherry picked from commit 5c6662f3e7)
This commit is contained in:
Martin 2023-12-30 20:03:06 +01:00
parent 9bef988478
commit 08fac03972
4 changed files with 176 additions and 0 deletions

View File

@ -350,6 +350,7 @@ type
//function IsValidTypeCast: Boolean; override;
function GetFieldFlags: TFpValueFieldFlags; override;
function GetAsCardinal: QWord; override;
function GetAsInteger: Int64; override;
procedure SetAsCardinal(AValue: QWord); override;
function GetAsString: AnsiString; override;
procedure SetAsString(AValue: AnsiString); override;
@ -368,6 +369,7 @@ type
protected
function GetFieldFlags: TFpValueFieldFlags; override;
function GetAsCardinal: QWord; override;
function GetAsInteger: Int64; override;
function GetAsString: AnsiString; override;
function IsValidTypeCast: Boolean; override;
function GetKind: TDbgSymbolKind; override;
@ -2906,6 +2908,15 @@ begin
FValue := Result;
end;
function TFpValueDwarfEnum.GetAsInteger: Int64;
var
Size: TFpDbgValueSize;
begin
Result := GetAsCardinal;
if GetSize(Size) then
Result := SignExtend(QWord(Result), Size);
end;
procedure TFpValueDwarfEnum.SetAsCardinal(AValue: QWord);
var
Size: TFpDbgValueSize;
@ -2979,6 +2990,11 @@ begin
Result := FOwnerVal.OrdinalValue;
end;
function TFpValueDwarfEnumMember.GetAsInteger: Int64;
begin
Result := FOwnerVal.OrdinalValue;
end;
function TFpValueDwarfEnumMember.GetAsString: AnsiString;
begin
Result := FOwnerVal.Name;

View File

@ -512,6 +512,8 @@ operator - (const AnAddr: TFpDbgMemLocation; AVal: QWord): TFpDbgMemLocation; i
function LocToAddr(const ALocation: TFpDbgMemLocation): TDbgPtr; inline; // does not check valid
function LocToAddrOrNil(const ALocation: TFpDbgMemLocation): TDbgPtr; inline; // save version
function SignExtend(ASrcVal: QWord; ASrcSize: TFpDbgValueSize): Int64;
//function EmptyMemReadOpts:TFpDbgMemReadOptions;
function dbgs(const ALocation: TFpDbgMemLocation): String; overload;
@ -900,6 +902,26 @@ begin
Result := 0;
end;
function SignExtend(ASrcVal: QWord; ASrcSize: TFpDbgValueSize): Int64;
var
SourceFullSize, SBit: Int64;
b: TBitSize;
begin
Result := Int64(ASrcVal);
SourceFullSize := SizeToFullBytes(ASrcSize);
if SourceFullSize = 0 then
exit;
b := ASrcSize.BitSize;
SBit := 8 * SourceFullSize;
if b > 0 then
SBit := SBit + b - 8;
if (ASrcVal and (1 shl (SBit-1)) ) <> 0 then
Result := Result or (int64(-1) shl SBit);
end;
//function {%H-}EmptyMemReadOpts: TFpDbgMemReadOptions;
//begin
// //

View File

@ -4829,6 +4829,42 @@ function TFpPascalExpressionPartOperatorCompare.DoGetResultValue: TFpValue;
else
SetError('= not supported');
end;
function CheckEnumCompatible(AName: String; AExpVal: Integer; AnEnum: TFpValue): boolean;
var
m, t: TFpSymbol;
begin
Result := AName = ''; // un-named / maybe invalid ordinal value
if Result then
exit;
t := AnEnum.TypeInfo;
Result := t = nil;
if Result then // TODO: TFpValueDwarfEnumMember currently does not have type info
exit;
m := t.NestedSymbolByName[AName];
Result := m <> nil;
if not Result then
exit;
Result := m.HasOrdinalValue and (m.OrdinalValue = AExpVal);
end;
function EnumEqual(AnEnumVal, AOtherVal: TFpValue; AReverse: Boolean = False): TFpValue;
begin
Result := nil;
if (AOtherVal.Kind in [skEnum, skEnumValue]) and
(AnEnumVal.FieldFlags * [svfInteger, svfCardinal, svfOrdinal] <> []) and
(AOtherVal.FieldFlags * [svfInteger, svfCardinal, svfOrdinal] <> [])
then begin
if CheckEnumCompatible(AnEnumVal.AsString, AnEnumVal.AsInteger, AOtherVal) and
CheckEnumCompatible(AOtherVal.AsString, AOtherVal.AsInteger, AnEnumVal)
then
Result := TFpValueConstBool.Create((AnEnumVal.AsInteger = AOtherVal.AsInteger) xor AReverse)
else
SetError('type mismatch between enum');
end
else
SetError('= not supported');
end;
function IntGreaterThanValue(AIntVal, AOtherVal: TFpValue; AReverse: Boolean = False): TFpValue;
begin
@ -4868,6 +4904,23 @@ function TFpPascalExpressionPartOperatorCompare.DoGetResultValue: TFpValue;
else
SetError('= not supported');
end;
function EnumGreaterThanValue(AnEnumVal, AOtherVal: TFpValue; AReverse: Boolean = False): TFpValue;
begin
Result := nil;
if (AOtherVal.Kind in [skEnum, skEnumValue]) and
(AnEnumVal.FieldFlags * [svfInteger, svfCardinal, svfOrdinal] <> []) and
(AOtherVal.FieldFlags * [svfInteger, svfCardinal, svfOrdinal] <> [])
then begin
if CheckEnumCompatible(AnEnumVal.AsString, AnEnumVal.AsInteger, AOtherVal) and
CheckEnumCompatible(AOtherVal.AsString, AOtherVal.AsInteger, AnEnumVal)
then
Result := TFpValueConstBool.Create((AnEnumVal.AsInteger > AOtherVal.AsInteger) xor AReverse)
else
SetError('type mismatch between enum');
end
else
SetError(GetText+' not supported');
end;
function IntSmallerThanValue(AIntVal, AOtherVal: TFpValue; AReverse: Boolean = False): TFpValue;
begin
@ -4907,6 +4960,23 @@ function TFpPascalExpressionPartOperatorCompare.DoGetResultValue: TFpValue;
else
SetError('= not supported');
end;
function EnumSmallerThanValue(AnEnumVal, AOtherVal: TFpValue; AReverse: Boolean = False): TFpValue;
begin
Result := nil;
if (AOtherVal.Kind in [skEnum, skEnumValue]) and
(AnEnumVal.FieldFlags * [svfInteger, svfCardinal, svfOrdinal] <> []) and
(AOtherVal.FieldFlags * [svfInteger, svfCardinal, svfOrdinal] <> [])
then begin
if CheckEnumCompatible(AnEnumVal.AsString, AnEnumVal.AsInteger, AOtherVal) and
CheckEnumCompatible(AOtherVal.AsString, AOtherVal.AsInteger, AnEnumVal)
then
Result := TFpValueConstBool.Create((AnEnumVal.AsInteger < AOtherVal.AsInteger) xor AReverse)
else
SetError('type mismatch between enum');
end
else
SetError(GetText+' not supported');
end;
function SymDiffSets(ASetVal, AOtherVal: TFpValue): TFpValue;
var
@ -4980,6 +5050,8 @@ begin
Result := CharDataEqualToValue(tmp1, tmp2, (s = '<>'));
skSet: Result := SetEqual(tmp1, tmp2, (s = '<>'));
skBoolean: Result := BoolEqual(tmp1, tmp2, (s = '<>'));
skEnum, skEnumValue:
Result := EnumEqual(tmp1, tmp2, (s = '<>'));
end;
end
else
@ -4994,6 +5066,8 @@ begin
Result := CharDataGreaterThanValue(tmp1, tmp2, (s = '<='));
skString, skAnsiString, skWideString, skChar{, skWideChar}:
Result := CharDataGreaterThanValue(tmp1, tmp2, (s = '<='));
skEnum, skEnumValue:
Result := EnumGreaterThanValue(tmp1, tmp2, (s = '<='));
end;
end
else
@ -5008,6 +5082,8 @@ begin
Result := CharDataSmallerThanValue(tmp1, tmp2, (s = '>='));
skString, skAnsiString, skWideString, skChar{, skWideChar}:
Result := CharDataSmallerThanValue(tmp1, tmp2, (s = '>='));
skEnum, skEnumValue:
Result := EnumSmallerThanValue(tmp1, tmp2, (s = '>='));
end;
end
else
@ -5108,6 +5184,18 @@ begin
exit
end;
if (tmp.Kind in [skType]) and
(tmp.DbgSymbol <> nil) and (tmp.DbgSymbol.Kind in [skEnum])
then begin
Result := tmp.MemberByName[MemberName];
if Result <> nil then begin
{$IFDEF WITH_REFCOUNT_DEBUG}Result.DbgRenameReference(nil, 'DoGetResultValue'){$ENDIF};
exit;
end;
SetError(fpErrNoMemberWithName, [MemberName]);
exit
end;
if (tmp.Kind = skUnit) or
( (tmp.DbgSymbol <> nil) and (tmp.DbgSymbol.Kind = skUnit) )
then begin

View File

@ -3589,6 +3589,52 @@ procedure TTestWatches.TestWatchesExpression;
t.Add(AName, p+'ShortInt'+e +' and '+ p+'Word'+e, weCardinal((50+n) and (1000+n)) );
t.Add(AName, p+'ShortInt'+e +' and '+ IntToStr(1002+n), weCardinal((50+n) and (1002+n)) );
t.Add('ENUM-EQ: ', p+'Enum = eNVaL2', weBool(False));
t.Add('ENUM-EQ: ', p+'Enum = eNVaL3', weBool(True));
t.Add('ENUM-EQ: ', p+'Enum = TEnum.eNVaL2', weBool(False));
t.Add('ENUM-EQ: ', p+'Enum = TEnum.eNVaL3', weBool(True));
t.Add('ENUM-EQ: ', 'eNVaL2 = '+p+'Enum', weBool(False));
t.Add('ENUM-EQ: ', 'eNVaL3 = '+p+'Enum', weBool(True));
t.Add('ENUM-EQ: ', p+'Enum = '+p2+'Enum', weBool(True));
t.Add('ENUM-EQ: ', p+'Enum = '+p2+'EnumA', weBool(False));
t.Add('ENUM-EQ: ', 'eNVaL3 = eNVaL2', weBool(False));
t.Add('ENUM-EQ: ', 'eNVaL3 = eNVaL3', weBool(True));
t.Add('ENUM-EQ: ', 'TEnum('+p+'Enum) = eNVaL2', weBool(False));
t.Add('ENUM-EQ: ', 'TEnum('+p+'Enum) = eNVaL3', weBool(True));
t.Add('ENUM-EQ: ', p+'Enum = TEnum(1)', weBool(False));
t.Add('ENUM-EQ: ', p+'Enum = TEnum(2)', weBool(True));
t.Add('ENUM-EQ: ', 'TEnum(1) = '+p+'Enum', weBool(False));
t.Add('ENUM-EQ: ', 'TEnum(2) = '+p+'Enum', weBool(True));
t.Add('ENUM-EQ: ', 'TEnum(2) = TEnum(1)', weBool(False));
t.Add('ENUM-EQ: ', 'TEnum(2) = TEnum(2)', weBool(True));
t.Add('ENUM-EQ: ', 'TEnum(2) = eNVaL2', weBool(False));
t.Add('ENUM-EQ: ', 'TEnum(2) = eNVaL3', weBool(True));
t.Add('ENUM-EQ: ', p+'EnumA = '+p2+'Enum1', weBool(False));
t.Add('ENUM-EQ: ','ENVal2 = '+p2+'Enum1', weBool(True));
t.Add('ENUM-EQ: ','ENVal1 = '+p2+'Enum1', weBool(False));
t.Add('ENUM-Cmp: ', p+'Enum > eNVaL2', weBool(True));
t.Add('ENUM-Cmp: ', p+'Enum >= eNVaL2', weBool(True));
t.Add('ENUM-Cmp: ', p+'Enum > eNVaL3', weBool(False));
t.Add('ENUM-Cmp: ', p+'Enum >= eNVaL3', weBool(True));
t.Add('ENUM-Cmp: ', p+'Enum < eNVaL2', weBool(False));
t.Add('ENUM-Cmp: ', p+'Enum < eNVaL3', weBool(False));
t.Add('ENUM-Cmp: ', p+'Enum < eNVaL4', weBool(True));
t.Add('ENUM-Cmp: ', 'eNVaL2 < '+p+'Enum', weBool(True));
t.Add('ENUM-Cmp: ', 'eNVaL3 < '+p+'Enum', weBool(False));
t.Add('ENUM-Cmp: ', 'eNVaL3 < eNVaL2', weBool(False));
t.Add('ENUM-Cmp: ', 'eNVaL3 > eNVaL2', weBool(True));
t.Add('ENUM-Cmp: ', 'TEnum('+p+'Enum) > eNVaL2', weBool(True));
t.Add('ENUM-Cmp: ', 'TEnum('+p+'Enum) > eNVaL3', weBool(False));
t.Add('ENUM-Cmp: ', p+'Enum > TEnum(2)', weBool(False));
t.Add('ENUM-Cmp: ', p+'Enum > TEnum(1)', weBool(True));
t.Add('ENUM-Cmp: ', p+'Enum > TEnum(-1)', weBool(True));
for i := 0 to t.Count-1 do
t.Tests[i].IgnTypeName();
end;
@ -4333,6 +4379,10 @@ begin
t.Add('', op1+'True'+op2+'^boolean(1)^', weMatchErr('read.*mem|data.*location'));
end;
t.Add('Diff ENUM types: ','gvEnum2 = gvEnum', weMatchErr('type'));
t.Add('Diff ENUM types: ','gvEnum2 = gvEnum1', weMatchErr('type'));
t.Add('Diff ENUM types: ','gvEnum2 = EnVal2', weMatchErr('type'));
t.EvaluateWatches;
t.CheckResults;