В этом посте я продолжу анализ библиотек поставляемых с Delphi. В предыдущих сериях я рассмотрел Delphi VCL и RTL. Как обычно я постараюсь найти все самое интересное и пропущу разнообразные мелочи, иначе этот пост получится слишком длинным. Все примеры кода в этом посте касаются Delphi XE8 (версия 22.0.19027.8951).
W517 Variable 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;
И то же самое в другом модуле.
procedure TStrokeCube.ReadDiffuse(Reader: TReader);
var
Color: Integer;
begin
IdentToAlphaColor(Reader.ReadIdent, Color);
{$R-}
Color := TAlphaColor(Color);
{$R+}
end;
Это одно из тех многочисленных предупреждений «переменная скрывает поле класса», о которых я говорил в предыдущем посте. В этом случае мы действительно видим баг. Классы TLight и TStrokeCube имеют свойство Color (типа TAlphaColor, конечно). Так что я предполагаю, что на самом деле имелось ввиду что-то вроде «Self.Color := TAlphaColor(Color)», но лучше просто переименовать переменную. Использовать одинаковые имена для переменных и полей класса — это очень плохой стиль. И Embarcadero, к сожалению, им злоупотребляет. Часто это совершенно не вредит, но иногда ведет к трудноотлавливаемым багам вроде этого. Просто посмотрите на этот код, запомните и никогда так не делайте. Никогда.
W511 Object created in TRY block
begin
if ([csDesigning, csDestroying, csLoading, csUpdating] * ComponentState <> []) or
(FUpdating > 0) then Exit;
{ Update objects in form }
try
Comparer := TComparerTFmxObject.Create;
ClientList := TTObjInfoList.Create(Comparer);
Bucket := TDictionary<TObject, TObject>.Create;
for InitiatedCount := 0 to 7 do
begin
if CollectActionClients(ClientList) = 0 then
Break;
ClientList.Sort;
for I := 0 to ClientList.Count - 1 do
ClientList[I].ActionClient.InitiateAction;
ClientList.Clear;
end;
finally
FreeAndNil(ClientList);
FreeAndNil(Bucket);
end;
end;
Приложение может вызвать исключение до того как ссылка на экземпляр класса будет присвоена переменным ClientList и/или Bucket. Это значит, что в блоке finally может быть попытка освободить объекты, которые не создавались.
W523 Interface declared without a GUID
IModelImporter = interface
function GetDescription: string;
function GetExt: string;
function LoadFromFile(const AFileName: string; out AMesh: TMeshDynArray;
const AOwner: TComponent): Boolean;
end;
IFMXUISwitch = interface(UISwitch)
{ Touches }
procedure touchesBegan(touches: NSSet; withEvent: UIEvent); cdecl;
procedure touchesCancelled(touches: NSSet; withEvent: UIEvent); cdecl;
procedure touchesEnded(touches: NSSet; withEvent: UIEvent); cdecl;
procedure touchesMoved(touches: NSSet; withEvent: UIEvent); cdecl;
procedure ValueChanged; cdecl;
end;
Не баг на самом деле, но так как интерфейсам не присвоен GUID, то они не могут быть использованы с функцией Supports или оператором As. Может быть стоит добавить GUID, почему нет?
W510 Values on both sides of the operator are equal
function SamePosition(const APosition1, APosition2: TPosition): Boolean; overload;
begin
Result := (APosition1.X = APosition2.X) and (APosition1.Y = APosition1.Y);
end;
Предположу, что имелось ввиду «APosition1.Y = APosition2.Y».
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
Два одинаковых присвоения одной переменной подряд. Вероятно не баг, просто неаккуратная копипаста.
W503 Assignment right hand side is equal to its left hand side
if X1 > X2 then
X1 := X1;
if Y1 > Y2 then
Y1 := Y2;
Предположу, что имелось ввиду «X1 := X2».
if (Self.Form <> nil) and (Self.Form.Handle <> nil) then
Self.Form := Self.Form;
Не знаю что здесь должно было быть (Self.Form здесь — это поле record’а).
И еще одно похожее место.
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;
Что здесь имелось ввиду?
W513 Format parameter count mismatch
function TCustomValueRange.GetNamePath: string;
begin
Result := Format( 'Value: %0:*.*f (%1:*.*f..%2:*.*f)', [Value, Min, Max]);
end;
Строка форматирования неправильная. При выполнении этого кода будет сообщение об ошибке.
W505 Empty THEN block
if FoundValue.Count > 1 then
else if FoundValue.Count > 0 then
PropValues[Name] := FoundValue[0];
Этот код очень странно выглядит. Вероятно его можно заменить на что-то такое: «If FoundValue.Count = 1 then PropValues[Name] := FoundValue[0]».
Ну вот и все на сегодня. Используйте FixInsight, чтобы найти баги до того как ваши пользователи их найдут :)