В этом посте я продолжу анализ библиотек поставляемых с Delphi. В прошлый раз мы заглянули внутрь Delphi VCL, а в этот раз будем разглядывать RTL. Я снова пропущу всякие мелочи и постараюсь сосредоточиться на самом интересном. Все примеры кода в этом посте касаются Delphi XE7 (версия 21.0.17017.3725).

W503 Assignment right hand side is equal to its left hand side

  constructor TNativeDownloader.Create(PublicKey: string; Salt: array of Byte; MainFile, PatchFile: TApkFileInfo);
  begin
    FMainFile := MainFile;
    FPatchFile := FPatchFile;
    FDownloader := TJNativeDownloaderLauncher.JavaClass.init(StringToJString(PublicKey), ByteArrayToJArray(Salt),
      CreateApkList(MainFile, PatchFile));
    Create;
  end;

Я думаю, тут должно было быть «FPatchFile := PatchFile».

W501 Empty EXCEPT block

  try
    Assert(FConnections.Count = 0); // All connections should have been removed
  except
  end;

Это не ошибка, просто непонятная какая-то ерунда :)

W517 Variable hides a class field, method or property

procedure TTask.ExecuteReplicates(Root: TTask);
var
                                     
//  ReplicasQuitting: Boolean;
  ReplicaProc: TProc;
begin
//  ReplicasQuitting := False;
  ReplicaProc := procedure
    var
      CurrentTask, ChildTask: ITask;
    begin
      CurrentTask := CurrentTask;
      if not Root.ShouldCreateReplica {or ReplicasQuitting} then
        Exit;
      ChildTask := Root.CreateReplicaTask(ReplicaProc, Self, [TCreateFlag.Replicating, TCreateFlag.Replica]);
      ChildTask.Start;
      try
        Root.CallUserCode;
      except
        Root.HandleException(TTask(ChildTask), TObject(AcquireExceptionObject));
      end;
    end;
  ReplicaProc;
end;

Сообщение W517 довольно часто встречается при анализе и VCL, и RTL. Но это место, по-моему, самое интересное. В классе TTask есть метод под названием CurrentTask и переменная CurrentTask перекрывает этот метод. Кстати, тут на строке 1865 еще одно предупреждение: «W503 Assignment right hand side is equal to its left hand side».

То есть непонятно что имелось ввиду «CurrentTask := Self.CurrentTask» или просто эта переменная там без какого-то смысла? В любом случае код довольно странно выглядит и достоин того, чтобы на него внимательно взглянуть.

Я не могу процитировать все сообщений W517, их слишком много. Но давайте вернемся к VCL и взглянем на еще один фрагмент.

procedure TCustomTaskDialog.ShowHelpException(E: Exception);
var
  Msg: string;
  Flags: Integer;
  SubE: Exception;
begin
  Flags := MB_OK or MB_ICONSTOP;
  if Application.UseRightToLeftReading then
    Flags := Flags or MB_RTLREADING;
  // ... [skipped]

Это не баг. Но это запросто сможет стать багом, если код изменится. Например, этот код будет компилироваться даже если переменную Flags просто удалить (ведь в классе TCustomTaskDialog есть свойство с таким же именем). Или, например, можно легко ошибиться и использовать в этом методе переменную вместо одноименного свойства, либо наоборот.

W504 Missing INHERITED call in destructor

destructor TJavaImport.Destroy;
begin
  TJNIResolver.DeleteGlobalRef(GetObjectID);
end;

Снова немало сообщений о пропущенном «inherited» в конструкторе. Процитирую только один пример.

W508 Variable is assigned twice successively

      // Another thread could start traversing the list between when we set the
      // head to P and when we assign to P.Next.  Initializing P.Next to point
      // to itself will make others spin until we assign the tail to P.Next.
      P.Next := P;
      P.Next := PThreadInfo(AtomicExchange(Pointer(FHashTable[H]), Pointer(P)));

Насколько я понимаю, это не баг. Но это место достойно цитирования. Как-то я не задумывался, что с многопоточностью можно работать вот так. Очень интересно.

На сегодня у меня все. Если пост вам понравился, то дайте мне знать на какую библиотеку или фреймворк мне стоит взглянуть с помощью FixInsight в следующий раз. FMX? JEDI? Что-то еще?