mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-23 16:51:20 +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 IsValidTypeCast: Boolean; override;
|
||||||
function GetFieldFlags: TFpValueFieldFlags; override;
|
function GetFieldFlags: TFpValueFieldFlags; override;
|
||||||
function GetAsCardinal: QWord; override;
|
function GetAsCardinal: QWord; override;
|
||||||
|
function GetAsInteger: Int64; override;
|
||||||
procedure SetAsCardinal(AValue: QWord); override;
|
procedure SetAsCardinal(AValue: QWord); override;
|
||||||
function GetAsString: AnsiString; override;
|
function GetAsString: AnsiString; override;
|
||||||
procedure SetAsString(AValue: AnsiString); override;
|
procedure SetAsString(AValue: AnsiString); override;
|
||||||
@ -368,6 +369,7 @@ type
|
|||||||
protected
|
protected
|
||||||
function GetFieldFlags: TFpValueFieldFlags; override;
|
function GetFieldFlags: TFpValueFieldFlags; override;
|
||||||
function GetAsCardinal: QWord; override;
|
function GetAsCardinal: QWord; override;
|
||||||
|
function GetAsInteger: Int64; override;
|
||||||
function GetAsString: AnsiString; override;
|
function GetAsString: AnsiString; override;
|
||||||
function IsValidTypeCast: Boolean; override;
|
function IsValidTypeCast: Boolean; override;
|
||||||
function GetKind: TDbgSymbolKind; override;
|
function GetKind: TDbgSymbolKind; override;
|
||||||
@ -2906,6 +2908,15 @@ begin
|
|||||||
FValue := Result;
|
FValue := Result;
|
||||||
end;
|
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);
|
procedure TFpValueDwarfEnum.SetAsCardinal(AValue: QWord);
|
||||||
var
|
var
|
||||||
Size: TFpDbgValueSize;
|
Size: TFpDbgValueSize;
|
||||||
@ -2979,6 +2990,11 @@ begin
|
|||||||
Result := FOwnerVal.OrdinalValue;
|
Result := FOwnerVal.OrdinalValue;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TFpValueDwarfEnumMember.GetAsInteger: Int64;
|
||||||
|
begin
|
||||||
|
Result := FOwnerVal.OrdinalValue;
|
||||||
|
end;
|
||||||
|
|
||||||
function TFpValueDwarfEnumMember.GetAsString: AnsiString;
|
function TFpValueDwarfEnumMember.GetAsString: AnsiString;
|
||||||
begin
|
begin
|
||||||
Result := FOwnerVal.Name;
|
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 LocToAddr(const ALocation: TFpDbgMemLocation): TDbgPtr; inline; // does not check valid
|
||||||
function LocToAddrOrNil(const ALocation: TFpDbgMemLocation): TDbgPtr; inline; // save version
|
function LocToAddrOrNil(const ALocation: TFpDbgMemLocation): TDbgPtr; inline; // save version
|
||||||
|
|
||||||
|
function SignExtend(ASrcVal: QWord; ASrcSize: TFpDbgValueSize): Int64;
|
||||||
|
|
||||||
//function EmptyMemReadOpts:TFpDbgMemReadOptions;
|
//function EmptyMemReadOpts:TFpDbgMemReadOptions;
|
||||||
|
|
||||||
function dbgs(const ALocation: TFpDbgMemLocation): String; overload;
|
function dbgs(const ALocation: TFpDbgMemLocation): String; overload;
|
||||||
@ -900,6 +902,26 @@ begin
|
|||||||
Result := 0;
|
Result := 0;
|
||||||
end;
|
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;
|
//function {%H-}EmptyMemReadOpts: TFpDbgMemReadOptions;
|
||||||
//begin
|
//begin
|
||||||
// //
|
// //
|
||||||
|
@ -4829,6 +4829,42 @@ function TFpPascalExpressionPartOperatorCompare.DoGetResultValue: TFpValue;
|
|||||||
else
|
else
|
||||||
SetError('= not supported');
|
SetError('= not supported');
|
||||||
end;
|
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;
|
function IntGreaterThanValue(AIntVal, AOtherVal: TFpValue; AReverse: Boolean = False): TFpValue;
|
||||||
begin
|
begin
|
||||||
@ -4868,6 +4904,23 @@ function TFpPascalExpressionPartOperatorCompare.DoGetResultValue: TFpValue;
|
|||||||
else
|
else
|
||||||
SetError('= not supported');
|
SetError('= not supported');
|
||||||
end;
|
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;
|
function IntSmallerThanValue(AIntVal, AOtherVal: TFpValue; AReverse: Boolean = False): TFpValue;
|
||||||
begin
|
begin
|
||||||
@ -4907,6 +4960,23 @@ function TFpPascalExpressionPartOperatorCompare.DoGetResultValue: TFpValue;
|
|||||||
else
|
else
|
||||||
SetError('= not supported');
|
SetError('= not supported');
|
||||||
end;
|
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;
|
function SymDiffSets(ASetVal, AOtherVal: TFpValue): TFpValue;
|
||||||
var
|
var
|
||||||
@ -4980,6 +5050,8 @@ begin
|
|||||||
Result := CharDataEqualToValue(tmp1, tmp2, (s = '<>'));
|
Result := CharDataEqualToValue(tmp1, tmp2, (s = '<>'));
|
||||||
skSet: Result := SetEqual(tmp1, tmp2, (s = '<>'));
|
skSet: Result := SetEqual(tmp1, tmp2, (s = '<>'));
|
||||||
skBoolean: Result := BoolEqual(tmp1, tmp2, (s = '<>'));
|
skBoolean: Result := BoolEqual(tmp1, tmp2, (s = '<>'));
|
||||||
|
skEnum, skEnumValue:
|
||||||
|
Result := EnumEqual(tmp1, tmp2, (s = '<>'));
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -4994,6 +5066,8 @@ begin
|
|||||||
Result := CharDataGreaterThanValue(tmp1, tmp2, (s = '<='));
|
Result := CharDataGreaterThanValue(tmp1, tmp2, (s = '<='));
|
||||||
skString, skAnsiString, skWideString, skChar{, skWideChar}:
|
skString, skAnsiString, skWideString, skChar{, skWideChar}:
|
||||||
Result := CharDataGreaterThanValue(tmp1, tmp2, (s = '<='));
|
Result := CharDataGreaterThanValue(tmp1, tmp2, (s = '<='));
|
||||||
|
skEnum, skEnumValue:
|
||||||
|
Result := EnumGreaterThanValue(tmp1, tmp2, (s = '<='));
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -5008,6 +5082,8 @@ begin
|
|||||||
Result := CharDataSmallerThanValue(tmp1, tmp2, (s = '>='));
|
Result := CharDataSmallerThanValue(tmp1, tmp2, (s = '>='));
|
||||||
skString, skAnsiString, skWideString, skChar{, skWideChar}:
|
skString, skAnsiString, skWideString, skChar{, skWideChar}:
|
||||||
Result := CharDataSmallerThanValue(tmp1, tmp2, (s = '>='));
|
Result := CharDataSmallerThanValue(tmp1, tmp2, (s = '>='));
|
||||||
|
skEnum, skEnumValue:
|
||||||
|
Result := EnumSmallerThanValue(tmp1, tmp2, (s = '>='));
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -5108,6 +5184,18 @@ begin
|
|||||||
exit
|
exit
|
||||||
end;
|
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
|
if (tmp.Kind = skUnit) or
|
||||||
( (tmp.DbgSymbol <> nil) and (tmp.DbgSymbol.Kind = skUnit) )
|
( (tmp.DbgSymbol <> nil) and (tmp.DbgSymbol.Kind = skUnit) )
|
||||||
then begin
|
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 '+ 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(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
|
for i := 0 to t.Count-1 do
|
||||||
t.Tests[i].IgnTypeName();
|
t.Tests[i].IgnTypeName();
|
||||||
end;
|
end;
|
||||||
@ -4333,6 +4379,10 @@ begin
|
|||||||
t.Add('', op1+'True'+op2+'^boolean(1)^', weMatchErr('read.*mem|data.*location'));
|
t.Add('', op1+'True'+op2+'^boolean(1)^', weMatchErr('read.*mem|data.*location'));
|
||||||
end;
|
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.EvaluateWatches;
|
||||||
t.CheckResults;
|
t.CheckResults;
|
||||||
|
Loading…
Reference in New Issue
Block a user