mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-13 11:29:29 +02:00
FpDebug: Add comparing enum-values in watches "enum1 >= enum2"
(cherry picked from commit 5c6662f3e7
)
This commit is contained in:
parent
9bef988478
commit
08fac03972
@ -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;
|
||||
|
@ -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
|
||||
// //
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user