FixInsight vs FMX in Delphi 10 Seattle
Several month ago I analyzed Delphi frameworks (VCL, FMX and RTL) with FixInsight and have found a number of interesting pieces of code. In this post I want to repeat my investigation and take a look at the latest FMX code in Delphi 10 Seattle Update 1 (23.0.21418.4207). As usual I will try to skip minor issues and mention only the most interesting parts of code.
W528 Variable ‘I’ not used in FOR-loop
for I := 0 to FContent.ControlsCount - 1 do
begin
Ctrl := FContent.Controls[Index];
if (Ctrl.Align = TAlignLayout.None) and ([TAnchorKind.akRight, TAnchorKind.akBottom] * Ctrl.Anchors <> []) and
ControlList.TryGetValue(Ctrl, R) then
begin
// ...
This for-loop never uses ‘I’ variable. But it uses ‘Index’ instead (see line 558) which is a TFmxObject class property.
W528 Variable ‘J’ not used in FOR-loop
// Iterate through each control's list and remove gesture ID's
// that don't exist in the updated FCustomGestures list
for P in FControls do
for I := P.Value.Count - 1 downto 0 do
for J := 0 to FRecordedGestures.Count - 1 do
begin
if (P.Value[I].GestureType = TGestureType.Recorded) and
(FRecordedGestures.FindGesture(P.Value[I].GestureID) = nil)
then
P.Value.Delete(I);
end;
I have no idea what’s the purpose of this nested for-loop. Let me know if it’s a bug or not.
W511 Object ‘LinePath’ created in TRY block
for I := 0 to FFrame3D.Count - 1 do
try
LinePath := TPathData.Create;
LLine := FFrame3D[I];
LineAdvance := 0;
LineVerticalAdvance := 0;
No, it’s not that case when you set a variable to nil before a try block :)
W508 Variable is assigned twice successively
P := Content.LocalToAbsolute(BottomRight);
P := AItem.ParentControl.AbsoluteToLocal(Content.LocalToAbsolute(BottomRight));
Not a bug actually, but is the first assignment really needed?
And one more:
Difference := [];
Difference := Value - FInteractiveGestures;
Now bad news.
Unfortunately some of the issues I have reported last time were not fixed. So I have to repeat and update.
W517 Variable ‘Color’ hides a class field, method or property
procedure TLight.ReadDiffuse(Reader: TReader);
var
Color: Integer;
begin
IdentToAlphaColor(Reader.ReadIdent, Color);
{$R-}
Color := TAlphaColor(Color);
{$R+}
end;
Variable ‘Color’ hides the TLight.Color property. So I think line 2759 should be “Self.Color := TAlphaColor(Color);”
And the same again:
procedure TStrokeCube.ReadMaterialDiffuse(Reader: TReader);
var
Color: Integer;
begin
IdentToAlphaColor(Reader.ReadIdent, Color);
{$R-}
Color := TAlphaColor(Color);
{$R+}
end;
W508 Variable is assigned twice successively
FPixelShader := TShaderManager.RegisterShaderFromData('gouraud.fps', TContextShaderKind.PixelShader, '', [
TContextShaderSource.Create(TContextShaderArch.DX9, [
$00, $02, $FF, $FF, $FE, $FF, $32, $00, $43, $54, $41, $42, $1C, $00, $00, $00, $9F, $00, $00, $00, $00, $02, $FF, $FF, $03, $00, $00, $00, $1C, $00, $00, $00, $00, $01, $00, $20, $98, $00, $00, $00,
// skipped
FPixelShader := TShaderManager.RegisterShaderFromData('gouraud.fps', TContextShaderKind.PixelShader, '', [
TContextShaderSource.Create(TContextShaderArch.DX9, [
$00, $02, $FF, $FF, $FE, $FF, $32, $00, $43, $54, $41, $42, $1C, $00, $00, $00, $9F, $00, $00, $00, $00, $02, $FF, $FF, $03, $00, $00, $00, $1C, $00, $00, $00, $00, $01, $00, $20, $98, $00, $00, $00,
// skipped
Two assignments in a row, probably not an issue, just a sloppy copy-paste.
W503 Assignment right hand side is equal to its left hand side
if X1 > X2 then
X1 := X1;
if Y1 > Y2 then
Y1 := Y2;
I guess, it should be “X1 := X2”.
if (Self.Form <> nil) and (Self.Form.Handle <> nil) then
Self.Form := Self.Form;
Not sure what was meant to be there (Self.Form is a record field).
And one more.
if FNew.FFrequency <> 0 then
FNew.FValue := Round(FNew.FValue / FNew.FFrequency) * FNew.FFrequency
else
FNew.FValue := FNew.FValue;
W510 Values on both sides of the operator are equal
if RegionSize = RegionSize then
begin
SetLength(UpdateRects, RegionData.rdh.nCount);
for i := 0 to RegionData.rdh.nCount - 1 do
begin
R := PRgnRects(@RegionData.buffer[0])[i];
UpdateRects[i] := RectF(R.Left, R.Top, R.Right, R.Bottom);
end;
end;
Not sure what was meant to be there. The same code in FMX.Platform.Win.Style.pas
if RegionSize = RegionSize then
begin
SetLength(UpdateRects, RegionData.rdh.nCount);
for I := 0 to RegionData.rdh.nCount - 1 do
begin
R := PRgnRects(@RegionData.buffer[0])[I];
UpdateRects[I] := RectF(R.Left, R.Top, R.Right, R.Bottom);
end;
end;
Copy and paste?
W513 Format parameter count mismatch
function TCustomValueRange.GetNamePath: string; begin Result := Format( 'Value: %0:*.*f (%1:*.*f..%2:*.*f)', [Value, Min, Max]); end;
The format string is incorrect. This code will raise an exception if you try to execute it.
W505 Empty THEN block
if FoundValue.Count > 1 then
else if FoundValue.Count > 0 then
PropValues[Name] := FoundValue[0];
This looks strange, perhaps it could be replaced with a simple “If FoundValue.Count = 1 then PropValues[Name] := FoundValue[0]”.
That’s all. A good reason to use FixInsight, isn’t it? :)

> A good reason to use FixInsight, isn’t it? :)
Yes. And maybe a good reason not to use FMX (yet)…