From 337d747d4dbd781a30d1b64afbe9f9d9d871ec77 Mon Sep 17 00:00:00 2001
From: Martin <laz.git@mfriebe.de>
Date: Sun, 1 Dec 2024 00:45:46 +0100
Subject: [PATCH] IDE, Project: refactored unit lists for units with specific
 flags.

---
 components/buildintf/projectintf.pas |  39 +++-
 ide/addtoprojectdlg.pas              |   6 +-
 ide/buildmanager.pas                 |  13 +-
 ide/codebrowser.pas                  |   6 +-
 ide/customformeditor.pp              |   6 +-
 ide/ideinfodlg.pas                   |   6 +-
 ide/main.pp                          |  85 ++++----
 ide/packages/ideproject/project.pp   | 280 +++++++++++++++------------
 ide/projectinspector.pas             |  10 +-
 ide/searchfrm.pas                    |   6 +-
 ide/sourcefilemanager.pas            |  21 +-
 ide/useunitdlg.pas                   |   4 +-
 packager/pkgmanager.pas              |   8 +-
 13 files changed, 245 insertions(+), 245 deletions(-)

diff --git a/components/buildintf/projectintf.pas b/components/buildintf/projectintf.pas
index b2edb35d74..d229aa0a03 100644
--- a/components/buildintf/projectintf.pas
+++ b/components/buildintf/projectintf.pas
@@ -16,7 +16,7 @@ unit ProjectIntf;
 interface
 
 uses
-  Classes, SysUtils, Contnrs, System.UITypes,
+  Classes, SysUtils, fgl, Contnrs, System.UITypes,
   // LazUtils
   FileUtil, LazFileUtils, LazFileCache, LazMethodList, AvgLvlTree,
   // BuildIntf
@@ -498,6 +498,43 @@ type
     property BuildModes[Index: integer]: TLazProjectBuildMode read GetLazBuildModes;
   end;
 
+  { TLazProjectFileList }
+
+  TLazProjectFileList = class(specialize TFPGList<TLazProjectFile>)
+  public type
+    TLazProjectFileListEnumerator = object abstract
+    protected
+      FList: TLazProjectFileList;
+      FData: integer;
+      FCurrent, FNext: TLazProjectFile;
+      function GetCurrent: TLazProjectFile; virtual; abstract;
+    public
+      function MoveNext: Boolean; virtual; abstract;
+      property Current: TLazProjectFile read GetCurrent;
+    end;
+    TLazProjectFileListEnumeration = object abstract
+    protected
+      FEnumerator: TLazProjectFileListEnumerator;
+    public
+      //constructor Create;
+      function GetEnumerator: TLazProjectFileListEnumerator; virtual; abstract;
+    end;
+  protected
+    FOwner: TLazProject;
+    function GetFilesBelongingToProject: TLazProjectFileListEnumeration; virtual; abstract;
+    function GetFilesLoaded: TLazProjectFileListEnumeration; virtual; abstract;
+    function GetFilesWithComponent: TLazProjectFileListEnumeration; virtual; abstract;
+    function GetFilesWithEditorIndex: TLazProjectFileListEnumeration; virtual; abstract;
+    function GetFilesWithRevertLock: TLazProjectFileListEnumeration; virtual; abstract;
+  public
+    property Owner: TLazProject read FOwner;
+    property FilesBelongingToProject: TLazProjectFileListEnumeration read GetFilesBelongingToProject;
+    property FilesWithEditorIndex: TLazProjectFileListEnumeration read GetFilesWithEditorIndex;
+    property FilesWithComponent: TLazProjectFileListEnumeration read GetFilesWithComponent;
+    property FilesLoaded: TLazProjectFileListEnumeration read GetFilesLoaded;
+    property FilesWithRevertLock: TLazProjectFileListEnumeration read GetFilesWithRevertLock;
+  end;
+
   { TLazProject - interface class to a Lazarus project }
 
   TProjectFileSearchFlag = (
diff --git a/ide/addtoprojectdlg.pas b/ide/addtoprojectdlg.pas
index 4e644d3779..f8d31a82cf 100644
--- a/ide/addtoprojectdlg.pas
+++ b/ide/addtoprojectdlg.pas
@@ -42,7 +42,7 @@ uses
   // IDEIntf
   IDEWindowIntf,
   // IDE
-  LazarusIDEStrConsts, IDEDialogs, Project, ProjPackChecks;
+  LazarusIDEStrConsts, IDEDialogs, ProjectIntf, Project, ProjPackChecks;
   
 type
   { TAddToProjectDialog }
@@ -168,15 +168,13 @@ var
 begin
   AddFileListView.Items.BeginUpdate;
   if fProject<>nil then begin
-    CurFile:=fProject.FirstUnitWithEditorIndex;
-    while CurFile<>nil do begin
+    for TLazProjectFile(CurFile) in fProject.UnitsWithEditorIndex do begin
       if (not CurFile.IsPartOfProject) and (not CurFile.IsVirtual) then begin
         NewFilename:=CreateRelativePath(CurFile.Filename,fProject.Directory);
         NewListItem:=AddFileListView.Items.Add;
         NewListItem.Caption:=NewFilename;
         NewListItem.Selected:=True;
       end;
-      CurFile:=CurFile.NextUnitWithEditorIndex;
     end;
   end;
   AddFileListView.Items.EndUpdate;
diff --git a/ide/buildmanager.pas b/ide/buildmanager.pas
index a3c41e4bb1..57c9689f39 100644
--- a/ide/buildmanager.pas
+++ b/ide/buildmanager.pas
@@ -1548,8 +1548,7 @@ begin
     if Result<>mrNo then exit;
 
     // check project files
-    AnUnitInfo:=AProject.FirstPartOfProject;
-    while AnUnitInfo<>nil do begin
+    for TLazProjectFile(AnUnitInfo) in AProject.UnitsBelongingToProject do begin
       if EditorUnitInfoModified(AnUnitInfo) then
       begin
         if ConsoleVerbosity>=0 then
@@ -1582,16 +1581,13 @@ begin
           end;
         end;
       end;
-      AnUnitInfo:=AnUnitInfo.NextPartOfProject;
     end;
 
     // check all open editor files in unit/include path (maybe the user forgot
     // to add them to the project)
-    AnUnitInfo:=AProject.FirstUnitWithEditorIndex;
-    while AnUnitInfo<>nil do begin
+    for TLazProjectFile(AnUnitInfo) in AProject.UnitsWithEditorIndex do begin
       if CheckNonProjectEditorFile(AnUnitInfo) then
         exit(mrYes);
-      AnUnitInfo:=AnUnitInfo.NextUnitWithEditorIndex;
     end;
 
     // check project resources
@@ -2146,9 +2142,7 @@ begin
   // update project resource
   if Project1.MainUnitID>=0 then
     Project1.ProjResources.Regenerate(Project1.MainFileName, False, True, TestDir);
-  AnUnitInfo := Project1.FirstPartOfProject;
-  while AnUnitInfo<>nil do
-  begin
+  for TLazProjectFile(AnUnitInfo) in Project1.UnitsBelongingToProject do begin
     if AnUnitInfo.HasResources then begin
       case GetResourceType(AnUnitInfo) of
       rtLRS:
@@ -2162,7 +2156,6 @@ begin
         end;
       end;
     end;
-    AnUnitInfo := AnUnitInfo.NextPartOfProject;
   end;
 end;
 
diff --git a/ide/codebrowser.pas b/ide/codebrowser.pas
index 19052adf9b..b4b94e6cb2 100644
--- a/ide/codebrowser.pas
+++ b/ide/codebrowser.pas
@@ -58,7 +58,7 @@ uses
   LazFileUtils, LazUTF8, AvgLvlTree,
   // IDEIntf
   IDEWindowIntf, SrcEditorIntf, IDEMsgIntf, IDEDialogs, LazConfigStorage,
-  IDEHelpIntf, PackageIntf, IDECommands, LazIDEIntf, IDEExternToolIntf,
+  IDEHelpIntf, PackageIntf, IDECommands, LazIDEIntf, IDEExternToolIntf, ProjectIntf,
   IDEImagesIntf,
   // IDE
   Project, DialogProcs, PackageSystem, PackageDefs, LazarusIDEStrConsts,
@@ -1402,14 +1402,12 @@ var
     AnUnitInfo: TUnitInfo;
   begin
     if AProject=nil then exit;
-    AnUnitInfo:=AProject.FirstPartOfProject;
     //DebugLn(['AddFilesOfProject ',AnUnitInfo<>nil]);
-    while AnUnitInfo<>nil do begin
+    for TLazProjectFile(AnUnitInfo) in AProject.UnitsBelongingToProject do begin
       //DebugLn(['AddFilesOfProject ',AnUnitInfo.Filename]);
       if FilenameIsPascalUnit(AnUnitInfo.Filename)
       or (AnUnitInfo=aProject.MainUnitInfo) then
         AddFile(AnUnitInfo.Filename,false);
-      AnUnitInfo:=AnUnitInfo.NextPartOfProject;
     end;
   end;
   
diff --git a/ide/customformeditor.pp b/ide/customformeditor.pp
index 492be680ba..7e54ea7eca 100644
--- a/ide/customformeditor.pp
+++ b/ide/customformeditor.pp
@@ -49,7 +49,7 @@ uses
   // Codetools
   CodeCache, CodeTree, CodeToolManager, FindDeclarationTool,
   // BuildIntf
-  ComponentReg,
+  ComponentReg, ProjectIntf,
   // IDEIntf
   PropEdits, PropEditUtils, ObjectInspector, FormEditingIntf,
   UnitResources, IDEOptEditorIntf, IDEDialogs, ComponentEditors,
@@ -2407,8 +2407,7 @@ begin
     ComponentClass:=RegComp.ComponentClass;
   end else begin
     // search in open and hidden designer forms (e.g. nested frames)
-    AnUnitInfo:=Project1.FirstUnitWithComponent;
-    while AnUnitInfo<>nil do begin
+    for TLazProjectFile(AnUnitInfo) in Project1.UnitsWithComponent do begin
       Component:=AnUnitInfo.Component;
       if CompareText(Component.ClassName,ComponentClassName)=0 then
       begin
@@ -2416,7 +2415,6 @@ begin
         ComponentClass:=TComponentClass(Component.ClassType);
         break;
       end;
-      AnUnitInfo:=AnUnitInfo.NextUnitWithComponent;
     end;
   end;
   //if ComponentClass=nil then
diff --git a/ide/ideinfodlg.pas b/ide/ideinfodlg.pas
index cb885ad3be..9d0e2411e6 100644
--- a/ide/ideinfodlg.pas
+++ b/ide/ideinfodlg.pas
@@ -41,7 +41,7 @@ uses
   // IdeConfig
   TransferMacros, EnvironmentOpts, LazConf,
   // BuildIntf
-  MacroDefIntf, IDEExternToolIntf,
+  MacroDefIntf, IDEExternToolIntf, ProjectIntf,
   // IdeIntf
   IDEHelpIntf, IDEWindowIntf, LazIDEIntf,
   // IDE
@@ -398,8 +398,7 @@ begin
 
   // details
   HeaderWritten:=false;
-  aFile:=AProject.FirstPartOfProject;
-  while aFile<>nil do begin
+  for TLazProjectFile(aFile) in AProject.UnitsBelongingToProject do begin
     if aFile.Modified or aFile.SessionModified
     or ((aFile.Source<>nil) and aFile.Source.Modified)
     then begin
@@ -416,7 +415,6 @@ begin
         s:=s+' Source.Modified';
       sl.Add(s);
     end;
-    aFile:=aFile.NextPartOfProject;
   end;
   if HeaderWritten then
     sl.Add('');
diff --git a/ide/main.pp b/ide/main.pp
index a2cfe4cb64..f10e9b5852 100644
--- a/ide/main.pp
+++ b/ide/main.pp
@@ -1026,13 +1026,11 @@ var
 begin
   Result:=nil;
   if Project1=nil then exit;
-  AnUnitInfo:=Project1.FirstUnitWithComponent;
-  while AnUnitInfo<>nil do begin
+  for TLazProjectFile(AnUnitInfo) in Project1.UnitsWithComponent do begin
     if SysUtils.CompareText(aName,AnUnitInfo.Component.Name)=0 then begin
       Result:=AnUnitInfo.Component;
       exit;
     end;
-    AnUnitInfo:=AnUnitInfo.NextUnitWithComponent;
   end;
 end;
 
@@ -3852,9 +3850,7 @@ var
   ADesigner: TDesigner;
 begin
   if Project1=nil then exit;
-  AnUnitInfo:=Project1.FirstUnitWithComponent;
-  while AnUnitInfo<>nil do
-  begin
+  for TLazProjectFile(AnUnitInfo) in Project1.UnitsWithComponent do begin
     if AnUnitInfo.Component<>nil then
     begin
       CurDesignerForm:=FormEditor1.GetDesignerForm(AnUnitInfo.Component);
@@ -3869,7 +3865,6 @@ begin
         CurDesignerForm.Invalidate;
       end;
     end;
-    AnUnitInfo:=AnUnitInfo.NextUnitWithComponent;
   end;
 end;
 
@@ -4439,45 +4434,43 @@ var
   AbortFlag, ReadSaveFailFlag: boolean;
 begin
   AbortFlag:=false;
-  AnUnitInfo:=Project1.FirstPartOfProject;
-  while (AnUnitInfo<>nil) and (not AbortFlag) do
-  begin
+  for TLazProjectFile(AnUnitInfo) in Project1.UnitsBelongingToProject do begin
     ReadSaveFailFlag:=false;
-    if FileNameIsPascalSource(AnUnitInfo.Filename) then
-    begin
-      LFMFileName:=AnUnitInfo.UnitResourceFileformat.GetUnitResourceFilename(AnUnitInfo.Filename,true);
-      if FileExistsCached(LFMFileName) and (not AnUnitInfo.DisableI18NForLFM) then
+    repeat
+      if FileNameIsPascalSource(AnUnitInfo.Filename) then
       begin
-        OpenStatus:=DoOpenEditorFile(AnUnitInfo.Filename,-1,-1,[ofAddToRecent, ofDoLoadResource]);
-        if OpenStatus=mrOk then
+        LFMFileName:=AnUnitInfo.UnitResourceFileformat.GetUnitResourceFilename(AnUnitInfo.Filename,true);
+        if FileExistsCached(LFMFileName) and (not AnUnitInfo.DisableI18NForLFM) then
         begin
-          AnUnitInfo.Modified:=true;
-          WriteStatus:=DoSaveEditorFile(AnUnitInfo.Filename,[]);
-          //DebugLn(['TMainIDE.mnuProjectResaveFormsWithI18n Resaving form "',AnUnitInfo.Filename,'"']);
-          if WriteStatus<>mrOk then
+          OpenStatus:=DoOpenEditorFile(AnUnitInfo.Filename,-1,-1,[ofAddToRecent, ofDoLoadResource]);
+          if OpenStatus=mrOk then
+          begin
+            AnUnitInfo.Modified:=true;
+            WriteStatus:=DoSaveEditorFile(AnUnitInfo.Filename,[]);
+            //DebugLn(['TMainIDE.mnuProjectResaveFormsWithI18n Resaving form "',AnUnitInfo.Filename,'"']);
+            if WriteStatus<>mrOk then
+            begin
+              ReadSaveFailFlag:=true;
+              if (WriteStatus=mrAbort) or
+                (IDEMessageDialog(lisErrorSavingForm,
+                                  Format(lisCannotSaveForm,[AnUnitInfo.Filename]),
+                                  mtError, [mbRetry,mbAbort]) = mrAbort) then
+                  AbortFlag:=true;
+            end;
+          end
+          else
           begin
             ReadSaveFailFlag:=true;
-            if (WriteStatus=mrAbort) or
-              (IDEMessageDialog(lisErrorSavingForm,
-                                Format(lisCannotSaveForm,[AnUnitInfo.Filename]),
+            if (OpenStatus=mrAbort) or
+              (IDEMessageDialog(lisErrorOpeningForm,
+                                Format(lisCannotOpenForm,[AnUnitInfo.Filename]),
                                 mtError, [mbRetry,mbAbort]) = mrAbort) then
                 AbortFlag:=true;
           end;
-        end
-        else
-        begin
-          ReadSaveFailFlag:=true;
-          if (OpenStatus=mrAbort) or
-            (IDEMessageDialog(lisErrorOpeningForm,
-                              Format(lisCannotOpenForm,[AnUnitInfo.Filename]),
-                              mtError, [mbRetry,mbAbort]) = mrAbort) then
-              AbortFlag:=true;
         end;
       end;
-    end;
     //we try next file only if read and write were successful, otherwise we retry current file or abort
-    if not ReadSaveFailFlag then
-      AnUnitInfo:=AnUnitInfo.NextPartOfProject;
+    until not ReadSaveFailFlag;
   end;
 end;
 
@@ -4599,10 +4592,8 @@ begin
   Files := TFilenameToPointerTree.Create(false);
   FileList:=TStringList.Create;
   try
-    AnUnitInfo:=AProject.FirstPartOfProject;
-    while AnUnitInfo<>nil do begin
+    for TLazProjectFile(AnUnitInfo) in AProject.UnitsBelongingToProject do begin
       CurFilename:=AnUnitInfo.Filename;
-      AnUnitInfo:=AnUnitInfo.NextPartOfProject;
       if not FilenameIsAbsolute(CurFilename) then continue;
       if (AProject.MainFilename<>CurFilename)
       and (not FilenameHasPascalExt(CurFilename)) then
@@ -8838,14 +8829,12 @@ begin
   ActiveSourceEditor:=nil;
   ActiveUnitInfo:=nil;
   if (APersistent<>nil) and (Project1<>nil) then begin
-    ActiveUnitInfo:=Project1.FirstUnitWithComponent;
-    while ActiveUnitInfo<>nil do begin
+    for TLazProjectFile(ActiveUnitInfo) in Project1.UnitsWithComponent do begin
       if ActiveUnitInfo.Component=APersistent then begin
         if ActiveUnitInfo.OpenEditorInfoCount > 0 then
           ActiveSourceEditor := TSourceEditor(ActiveUnitInfo.OpenEditorInfo[0].EditorComponent);
         exit;
       end;
-      ActiveUnitInfo:=ActiveUnitInfo.NextUnitWithComponent;
     end;
   end;
 end;
@@ -9125,15 +9114,11 @@ end;
 procedure TMainIDE.CloseUnmodifiedDesigners;
 var
   AnUnitInfo: TUnitInfo;
-  NextUnitInfo: TUnitInfo;
 begin
   if Project1=nil then exit;
-  AnUnitInfo:=Project1.FirstUnitWithComponent;
-  while AnUnitInfo<>nil do begin
-    NextUnitInfo:=AnUnitInfo.NextUnitWithComponent;
+  for TLazProjectFile(AnUnitInfo) in Project1.UnitsWithComponent do begin
     if not AnUnitInfo.NeedsSaveToDisk(true) then
       CloseUnitComponent(AnUnitInfo,[]);
-    AnUnitInfo:=NextUnitInfo;
   end;
 end;
 
@@ -10236,11 +10221,9 @@ begin
             AProject:=TProject(Owners[i]);
             if AProject.MainUnitInfo<>nil then
               AddUnit(AProject.MainUnitInfo);
-            AnUnitInfo:=AProject.FirstPartOfProject;
-            while AnUnitInfo<>nil do begin
+            for TLazProjectFile(AnUnitInfo) in AProject.UnitsBelongingToProject do begin
               if AnUnitInfo<>AProject.MainUnitInfo then
                 AddUnit(AnUnitInfo);
-              AnUnitInfo:=AnUnitInfo.NextPartOfProject;
             end;
           end else if TObject(Owners[i]) is TLazPackage then begin
             APackage:=TLazPackage(Owners[i]);
@@ -13087,13 +13070,11 @@ var
   AnUnitInfo: TUnitInfo;
 begin
   if AComponent=nil then exit(nil);
-  AnUnitInfo:=Project1.FirstUnitWithComponent;
-  while AnUnitInfo<>nil do begin
+  for TLazProjectFile(AnUnitInfo) in Project1.UnitsWithComponent do begin
     if AnUnitInfo.Component=AComponent then begin
       Result:=AnUnitInfo;
       exit;
     end;
-    AnUnitInfo:=AnUnitInfo.NextUnitWithComponent;
   end;
   Result:=nil;
 end;
diff --git a/ide/packages/ideproject/project.pp b/ide/packages/ideproject/project.pp
index 5b11c8a1ae..c34de65e1a 100644
--- a/ide/packages/ideproject/project.pp
+++ b/ide/packages/ideproject/project.pp
@@ -326,17 +326,7 @@ type
     function GetLoadingComponent: boolean;
     function GetMarked: boolean;
     function GetModified: boolean;
-    function GetNextAutoRevertLockedUnit: TUnitInfo;
-    function GetNextLoadedUnit: TUnitInfo;
-    function GetNextPartOfProject: TUnitInfo;
-    function GetNextUnitWithComponent: TUnitInfo;
-    function GetNextUnitWithEditorIndex: TUnitInfo;
     function GetOpenEditorInfo(Index: Integer): TUnitEditorInfo;
-    function GetPrevAutoRevertLockedUnit: TUnitInfo;
-    function GetPrevLoadedUnit: TUnitInfo;
-    function GetPrevPartOfProject: TUnitInfo;
-    function GetPrevUnitWithComponent: TUnitInfo;
-    function GetPrevUnitWithEditorIndex: TUnitInfo;
     function GetRunFileIfActive: boolean;
     function GetSessionModified: boolean;
     function GetUnitResourceFileformat: TUnitResourcefileFormatClass;
@@ -447,18 +437,6 @@ type
   public
     { Properties }
     property UnitResourceFileformat: TUnitResourcefileFormatClass read GetUnitResourceFileformat;
-
-    // Unit lists
-    property NextUnitWithEditorIndex: TUnitInfo read GetNextUnitWithEditorIndex;
-    property PrevUnitWithEditorIndex: TUnitInfo read GetPrevUnitWithEditorIndex;
-    property NextUnitWithComponent: TUnitInfo read GetNextUnitWithComponent;
-    property PrevUnitWithComponent: TUnitInfo read GetPrevUnitWithComponent;
-    property NextLoadedUnit: TUnitInfo read GetNextLoadedUnit;
-    property PrevLoadedUnit: TUnitInfo read GetPrevLoadedUnit;
-    property NextAutoRevertLockedUnit: TUnitInfo read GetNextAutoRevertLockedUnit;
-    property PrevAutoRevertLockedUnit: TUnitInfo read GetPrevAutoRevertLockedUnit;
-    property NextPartOfProject: TUnitInfo read GetNextPartOfProject;
-    property PrevPartOfProject: TUnitInfo read GetPrevPartOfProject;
   public
     property Bookmarks: TFileBookmarks read FBookmarks write FBookmarks;
     property BuildFileIfActive: boolean read GetBuildFileIfActive
@@ -515,6 +493,39 @@ type
   end;
 
 
+  { TIdeLazProjectFileList }
+
+  TIdeLazProjectFileList = class(TLazProjectFileList)
+  public type
+
+    { TIdeLazProjectFileListEnumerator }
+
+    TIdeLazProjectFileListEnumerator = object(TLazProjectFileListEnumerator)
+    private
+      function GetCurrent: TLazProjectFile; virtual;
+    public
+      constructor Create(AList: TLazProjectFileList; AData: TUnitInfoList);
+      function MoveNext: Boolean; virtual;
+      property Current: TLazProjectFile read GetCurrent;
+    end;
+
+    { TIdeLazProjectFileListEnumeration }
+
+    TIdeLazProjectFileListEnumeration = object(TLazProjectFileListEnumeration)
+    public
+      constructor Create(AList: TLazProjectFileList; AData: TUnitInfoList);
+      function GetEnumerator: TLazProjectFileListEnumerator; virtual;
+    end;
+  protected
+    function GetFilesBelongingToProject: TLazProjectFileListEnumeration; override;
+    function GetFilesLoaded: TLazProjectFileListEnumeration; override;
+    function GetFilesWithComponent: TLazProjectFileListEnumeration; override;
+    function GetFilesWithEditorIndex: TLazProjectFileListEnumeration; override;
+    function GetFilesWithRevertLock: TLazProjectFileListEnumeration; override;
+  public
+    constructor Create(AnOwner: TLazProject);
+  end;
+
   //---------------------------------------------------------------------------
 
   { TProjectCompilationToolOptions }
@@ -822,7 +833,7 @@ type
     FStateFileDate: longint;
     FStateFlags: TLazProjectStateFlags;
     FStorePathDelim: TPathDelimSwitch;
-    FUnitList: TFPList;  // list of _all_ units (TUnitInfo)
+    FUnitList: TIdeLazProjectFileList;  // list of _all_ units (TUnitInfo)
     FOtherDefines: TStrings; // list of user selectable defines for custom options
     FUpdateLock: integer;
     FUseAsDefault: Boolean;
@@ -837,10 +848,11 @@ type
     function GetAllEditorsInfo(Index: Integer): TUnitEditorInfo;
     function GetCompilerOptions: TProjectCompilerOptions;
     function GetBaseCompilerOptions: TBaseCompilerOptions;
-    function GetFirstAutoRevertLockedUnit: TUnitInfo;
-    function GetFirstLoadedUnit: TUnitInfo;
-    function GetFirstPartOfProject: TUnitInfo;
-    function GetFirstUnitWithComponent: TUnitInfo;
+    function GetFilesBelongingToProject: TIdeLazProjectFileList.TLazProjectFileListEnumeration;
+    function GetFilesLoaded: TIdeLazProjectFileList.TLazProjectFileListEnumeration;
+    function GetFilesWithComponent: TIdeLazProjectFileList.TLazProjectFileListEnumeration;
+    function GetFilesWithEditorIndex: TIdeLazProjectFileList.TLazProjectFileListEnumeration;
+    function GetFilesWithRevertLock: TIdeLazProjectFileList.TLazProjectFileListEnumeration;
     function GetFirstUnitWithEditorIndex: TUnitInfo;
     function GetIDEOptions: TProjectIDEOptions;
     function GetMainFilename: String;
@@ -1137,12 +1149,8 @@ type
     property I18NExcludedOriginals: TStrings read FI18NExcludedOriginals;
     property UseLegacyLists: Boolean read GetUseLegacyLists;
     property ForceUpdatePoFiles: Boolean read FForceUpdatePoFiles write FForceUpdatePoFiles;
-    property FirstAutoRevertLockedUnit: TUnitInfo read GetFirstAutoRevertLockedUnit;
-    property FirstLoadedUnit: TUnitInfo read GetFirstLoadedUnit;
-    property FirstPartOfProject: TUnitInfo read GetFirstPartOfProject;
     property FirstRemovedDependency: TPkgDependency read FFirstRemovedDependency;
     property FirstRequiredDependency: TPkgDependency read FFirstRequiredDependency;
-    property FirstUnitWithComponent: TUnitInfo read GetFirstUnitWithComponent;
     property FirstUnitWithEditorIndex: TUnitInfo read GetFirstUnitWithEditorIndex;
     property IDAsString: string read GetIDAsString;
     property IDAsWord: string read GetIDAsWord;
@@ -1188,6 +1196,11 @@ type
     property OtherDefines: TStrings read FOtherDefines;
     property UpdateLock: integer read FUpdateLock;
     property UseAsDefault: Boolean read FUseAsDefault write FUseAsDefault; // for dialog only (used to store options once)
+    property UnitsBelongingToProject: TIdeLazProjectFileList.TLazProjectFileListEnumeration read GetFilesBelongingToProject;
+    property UnitsWithEditorIndex: TIdeLazProjectFileList.TLazProjectFileListEnumeration read GetFilesWithEditorIndex;
+    property UnitsWithComponent: TIdeLazProjectFileList.TLazProjectFileListEnumeration read GetFilesWithComponent;
+    property UnitsLoaded: TIdeLazProjectFileList.TLazProjectFileListEnumeration read GetFilesLoaded;
+    property UnitsWithRevertLock: TIdeLazProjectFileList.TLazProjectFileListEnumeration read GetFilesWithRevertLock;
   end;
 
 
@@ -2577,61 +2590,11 @@ begin
     or ((Source<>nil) and (Source.ChangeStep<>fSourceChangeStep));
 end;
 
-function TUnitInfo.GetNextAutoRevertLockedUnit: TUnitInfo;
-begin
-  Result:=fNext[uilAutoRevertLocked];
-end;
-
-function TUnitInfo.GetNextLoadedUnit: TUnitInfo;
-begin
-  Result:=fNext[uilLoaded];
-end;
-
-function TUnitInfo.GetNextPartOfProject: TUnitInfo;
-begin
-  Result:=fNext[uilPartOfProject];
-end;
-
-function TUnitInfo.GetNextUnitWithComponent: TUnitInfo;
-begin
-  Result:=fNext[uilWithComponent];
-end;
-
-function TUnitInfo.GetNextUnitWithEditorIndex: TUnitInfo;
-begin
-  Result:=fNext[uilWithEditorIndex];
-end;
-
 function TUnitInfo.GetOpenEditorInfo(Index: Integer): TUnitEditorInfo;
 begin
   Result := FEditorInfoList.OpenEditorInfos[Index];
 end;
 
-function TUnitInfo.GetPrevAutoRevertLockedUnit: TUnitInfo;
-begin
-  Result:=fPrev[uilAutoRevertLocked];
-end;
-
-function TUnitInfo.GetPrevLoadedUnit: TUnitInfo;
-begin
-  Result:=fPrev[uilLoaded];
-end;
-
-function TUnitInfo.GetPrevPartOfProject: TUnitInfo;
-begin
-  Result:=fPrev[uilPartOfProject];
-end;
-
-function TUnitInfo.GetPrevUnitWithComponent: TUnitInfo;
-begin
-  Result:=fPrev[uilWithComponent];
-end;
-
-function TUnitInfo.GetPrevUnitWithEditorIndex: TUnitInfo;
-begin
-  Result:=fPrev[uilWithEditorIndex];
-end;
-
 function TUnitInfo.GetRunFileIfActive: boolean;
 begin
   Result:=uifRunFileIfActive in FFlags;
@@ -2901,6 +2864,77 @@ begin
     Exclude(FFlags, uifSessionModified);
 end;
 
+{ TIdeLazProjectFileList.TIdeLazProjectFileListEnumerator }
+
+function TIdeLazProjectFileList.TIdeLazProjectFileListEnumerator.GetCurrent: TLazProjectFile;
+begin
+  Result := FCurrent;
+end;
+
+constructor TIdeLazProjectFileList.TIdeLazProjectFileListEnumerator.Create(
+  AList: TLazProjectFileList; AData: TUnitInfoList);
+begin
+  FList := AList;
+  FData := ord(AData);
+  FCurrent := nil;
+end;
+
+function TIdeLazProjectFileList.TIdeLazProjectFileListEnumerator.MoveNext: Boolean;
+begin
+  if FCurrent = nil then
+    FCurrent := (FList.Owner as TProject).fFirst[TUnitInfoList(FData)]
+  else
+    FCurrent := FNext;
+  Result := FCurrent <> nil;
+  if Result then
+    FNext := (FCurrent as TUnitInfo).fNext[TUnitInfoList(FData)];
+end;
+
+{ TIdeLazProjectFileList.TIdeLazProjectFileListEnumeration }
+
+constructor TIdeLazProjectFileList.TIdeLazProjectFileListEnumeration.Create(
+  AList: TLazProjectFileList; AData: TUnitInfoList);
+begin
+  TIdeLazProjectFileListEnumerator(FEnumerator).Create(AList, AData);
+end;
+
+function TIdeLazProjectFileList.TIdeLazProjectFileListEnumeration.GetEnumerator: TLazProjectFileListEnumerator;
+begin
+  Result := FEnumerator;
+end;
+
+{ TIdeLazProjectFileList }
+
+function TIdeLazProjectFileList.GetFilesBelongingToProject: TLazProjectFileListEnumeration;
+begin
+  TIdeLazProjectFileListEnumeration(Result).Create(Self, uilPartOfProject);
+end;
+
+function TIdeLazProjectFileList.GetFilesLoaded: TLazProjectFileListEnumeration;
+begin
+  TIdeLazProjectFileListEnumeration(Result).Create(Self, uilLoaded);
+end;
+
+function TIdeLazProjectFileList.GetFilesWithComponent: TLazProjectFileListEnumeration;
+begin
+  TIdeLazProjectFileListEnumeration(Result).Create(Self, uilWithComponent);
+end;
+
+function TIdeLazProjectFileList.GetFilesWithEditorIndex: TLazProjectFileListEnumeration;
+begin
+  TIdeLazProjectFileListEnumeration(Result).Create(Self, uilWithEditorIndex);
+end;
+
+function TIdeLazProjectFileList.GetFilesWithRevertLock: TLazProjectFileListEnumeration;
+begin
+  TIdeLazProjectFileListEnumeration(Result).Create(Self, uilAutoRevertLocked);
+end;
+
+constructor TIdeLazProjectFileList.Create(AnOwner: TLazProject);
+begin
+  FOwner := AnOwner;
+  inherited Create;
+end;
 
 { TProjectIDEOptions }
 
@@ -2981,7 +3015,7 @@ begin
   FPublishOptions:=TPublishProjectOptions.Create(Self);
   FRunParameters:=TRunParamsOptions.Create;
   Title := '';
-  FUnitList := TFPList.Create;  // list of TUnitInfo
+  FUnitList := TIdeLazProjectFileList.Create(Self);  // list of TUnitInfo
   FOtherDefines := TStringList.Create;
   FEnableI18N := False;
   FEnableI18NForLFM := True;
@@ -4552,27 +4586,12 @@ begin
   else Result:='';
 end;
 
-function TProject.GetFirstPartOfProject: TUnitInfo;
-begin
-  Result:=FFirst[uilPartOfProject];
-end;
-
-function TProject.GetFirstLoadedUnit: TUnitInfo;
-begin
-  Result:=fFirst[uilLoaded];
-end;
-
 procedure TProject.EmbeddedObjectModified(Sender: TObject);
 begin
   if ProjResources.Modified then
     Modified := True;
 end;
 
-function TProject.GetFirstAutoRevertLockedUnit: TUnitInfo;
-begin
-  Result:=fFirst[uilAutoRevertLocked];
-end;
-
 function TProject.GetAllEditorsInfo(Index: Integer): TUnitEditorInfo;
 begin
   Result := FAllEditorsInfoList[Index];
@@ -4589,6 +4608,31 @@ begin
   Result := TBaseCompilerOptions(FLazCompilerOptions);
 end;
 
+function TProject.GetFilesBelongingToProject: TIdeLazProjectFileList.TLazProjectFileListEnumeration;
+begin
+  Result := FUnitList.FilesBelongingToProject;
+end;
+
+function TProject.GetFilesLoaded: TIdeLazProjectFileList.TLazProjectFileListEnumeration;
+begin
+  Result := FUnitList.FilesLoaded;
+end;
+
+function TProject.GetFilesWithComponent: TIdeLazProjectFileList.TLazProjectFileListEnumeration;
+begin
+  Result := FUnitList.FilesWithComponent;
+end;
+
+function TProject.GetFilesWithEditorIndex: TIdeLazProjectFileList.TLazProjectFileListEnumeration;
+begin
+  Result := FUnitList.FilesWithEditorIndex;
+end;
+
+function TProject.GetFilesWithRevertLock: TIdeLazProjectFileList.TLazProjectFileListEnumeration;
+begin
+  Result := FUnitList.FilesWithRevertLock;
+end;
+
 procedure TProject.ClearBuildModes;
 begin
   ActiveBuildMode:=nil;
@@ -4602,11 +4646,6 @@ begin
   Result := ActiveBuildMode.Identifier;
 end;
 
-function TProject.GetFirstUnitWithComponent: TUnitInfo;
-begin
-  Result:=fFirst[uilWithComponent];
-end;
-
 function TProject.GetFirstUnitWithEditorIndex: TUnitInfo;
 begin
   Result:=fFirst[uilWithEditorIndex];
@@ -4823,11 +4862,9 @@ procedure TProject.GetAutoRevertLockedFiles(var ACodeBufferList: TFPList);
 var
   AnUnitInfo: TUnitInfo;
 begin
-  AnUnitInfo:=fFirst[uilAutoRevertLocked];
-  while (AnUnitInfo<>nil) do begin
+  for TLazProjectFile(AnUnitInfo) in FUnitList.FilesWithRevertLock do begin
     Add(AnUnitInfo.Source);
     Add(AnUnitInfo.SourceLFM);
-    AnUnitInfo:=AnUnitInfo.fNext[uilAutoRevertLocked];
   end;
 end;
 
@@ -5164,12 +5201,10 @@ begin
     DebugLn(['TProject.UpdateUnitComponentDependencies checking properties ...']);
     {$ENDIF}
     // find property dependencies
-    AnUnitInfo:=FirstUnitWithComponent;
-    while AnUnitInfo<>nil do begin
+    for TLazProjectFile(AnUnitInfo) in UnitsWithComponent do begin
       Search(AnUnitInfo,AnUnitInfo.Component);
       for i:=AnUnitInfo.Component.ComponentCount-1 downto 0 do
         Search(AnUnitInfo,AnUnitInfo.Component.Components[i]);
-      AnUnitInfo:=AnUnitInfo.NextUnitWithComponent;
     end;
     //WriteDebugReportUnitComponentDependencies('P ');
   end;
@@ -5181,8 +5216,7 @@ begin
     DebugLn(['TProject.UpdateUnitComponentDependencies checking designers ...']);
     {$ENDIF}
     // find designer dependencies
-    AnUnitInfo:=FirstUnitWithComponent;
-    while AnUnitInfo<>nil do begin
+    for TLazProjectFile(AnUnitInfo) in UnitsWithComponent do begin
       AnUnitInfo.FFlags:=AnUnitInfo.FFlags-
         [uifMarked,uifComponentIndirectlyUsedByDesigner,uifComponentUsedByDesigner];
       if FindRootDesigner(AnUnitInfo.Component)<>nil then begin
@@ -5191,17 +5225,14 @@ begin
         {$ENDIF}
         Include(AnUnitInfo.FFlags,uifComponentUsedByDesigner);
       end;
-      AnUnitInfo:=AnUnitInfo.NextUnitWithComponent;
     end;
     // mark all units that are used indirectly by a designer
-    AnUnitInfo:=FirstUnitWithComponent;
-    while AnUnitInfo<>nil do begin
+    for TLazProjectFile(AnUnitInfo) in UnitsWithComponent do begin
       if (uifComponentUsedByDesigner in AnUnitInfo.FFlags) then
       begin
         // mark all that use indirectly this designer
         DFSRequiredDesigner(AnUnitInfo,AnUnitInfo);
       end;
-      AnUnitInfo:=AnUnitInfo.NextUnitWithComponent;
     end;
     {$IFDEF VerboseTFrame}
     WriteDebugReportUnitComponentDependencies('UUCD ');
@@ -5280,15 +5311,13 @@ begin
       OwnerComponent:=OwnerComponent.Owner;
   end else
     OwnerComponent:=nil;
-  AnUnitInfo:=FirstUnitWithComponent;
-  while AnUnitInfo<>nil do begin
+  for TLazProjectFile(AnUnitInfo) in UnitsWithComponent do begin
     if csDestroying in AnUnitInfo.Component.ComponentState then continue;
     if AnUnitInfo.Component<>OwnerComponent then begin
       Search(AnUnitInfo,AnUnitInfo.Component);
       for i:=AnUnitInfo.Component.ComponentCount-1 downto 0 do
         Search(AnUnitInfo,AnUnitInfo.Component.Components[i]);
     end;
-    AnUnitInfo:=AnUnitInfo.NextUnitWithComponent;
   end;
 end;
 
@@ -5722,15 +5751,13 @@ begin
       DebugLn(['TProject.SomeDataModified CompilerOptions/BuildModes']);
     Exit;
   end;
-  AnUnitInfo:=FirstPartOfProject;
-  while AnUnitInfo<>nil do begin
+  for TLazProjectFile(AnUnitInfo) in UnitsBelongingToProject do begin
     if AnUnitInfo.Modified then
     begin
       if Verbose then
         DebugLn('TProject.SomeDataModified PartOfProject ',AnUnitInfo.Filename);
       Exit;
     end;
-    AnUnitInfo:=AnUnitInfo.NextPartOfProject;
   end;
   Result:=false;
 end;
@@ -6022,19 +6049,16 @@ begin
     SearchedFilename:=ExtractFilenameOnly(SearchedFilename);
 
   // search in files which are part of the project
-  Result:=FirstPartOfProject;
-  while Result<>nil do begin
+  for TLazProjectFile(Result) in UnitsBelongingToProject do begin
     if FilenameFits(Result.Filename) then exit;
-    Result:=Result.NextPartOfProject;
   end;
   // search in files opened in editor
   if not (siffDoNotCheckOpenFiles in SearchFlags) then begin
-    Result:=FirstUnitWithEditorIndex;
-    while Result<>nil do begin
+    for TLazProjectFile(Result) in UnitsWithEditorIndex do begin
       if FilenameFits(Result.Filename) then exit;
-      Result:=Result.NextUnitWithEditorIndex;
     end;
   end;
+  Result := nil;
 end;
 
 function TProject.FindFile(const AFilename: string;
@@ -6310,8 +6334,7 @@ begin
   end;
 
   if BestUnitInfo=nil then begin
-    AnUnitInfo:=FirstPartOfProject;
-    while AnUnitInfo<>nil do begin
+    for TLazProjectFile(AnUnitInfo) in UnitsBelongingToProject do begin
       if FileExistsCached(AnUnitInfo.Filename) then begin
         if (BestUnitInfo=nil)
         or (FilenameHasPascalExt(AnUnitInfo.Filename)
@@ -6320,7 +6343,6 @@ begin
           BestUnitInfo:=AnUnitInfo;
         end;
       end;
-      AnUnitInfo:=AnUnitInfo.NextPartOfProject;
     end;
   end;
   if BestUnitInfo<>nil then begin
diff --git a/ide/projectinspector.pas b/ide/projectinspector.pas
index bc6e5b7a2c..51659a4138 100644
--- a/ide/projectinspector.pas
+++ b/ide/projectinspector.pas
@@ -1184,21 +1184,17 @@ end;
 procedure TProjectInspectorForm.RemoveNonExistingFilesMenuItemClick(Sender: TObject);
 var
   AnUnitInfo: TUnitInfo;
-  NextUnitInfo: TUnitInfo;
   HasChanged: Boolean;
 begin
   if LazProject.IsVirtual then exit;
   BeginUpdate;
   try
     HasChanged:=false;
-    AnUnitInfo:=LazProject.FirstPartOfProject;
-    while AnUnitInfo<>nil do begin
-      NextUnitInfo:=AnUnitInfo.NextPartOfProject;
+    for TLazProjectFile(AnUnitInfo) in LazProject.UnitsBelongingToProject do begin
       if not (AnUnitInfo.IsVirtual or FileExistsUTF8(AnUnitInfo.Filename)) then begin
         AnUnitInfo.IsPartOfProject:=false;
         HasChanged:=true;
       end;
-      AnUnitInfo:=NextUnitInfo;
     end;
     if HasChanged then begin
       LazProject.Modified:=true;
@@ -1497,14 +1493,12 @@ begin
     FilterEdit.SortData:=SortAlphabetically;
     FilterEdit.ImageIndexDirectory:=ImageIndexDirectory;
     // collect and sort files
-    CurFile:=LazProject.FirstPartOfProject;
-    while CurFile<>nil do begin
+    for TLazProjectFile(CurFile) in LazProject.UnitsBelongingToProject do begin
       Filename:=CurFile.GetShortFilename(true);
       if Filename<>'' then Begin
         ANodeData:=FPropGui.CreateNodeData(penFile, CurFile.Filename, False);
         FilesBranch.AddNodeData(Filename, ANodeData, CurFile.Filename);
       end;
-      CurFile:=CurFile.NextPartOfProject;
     end;
   end;
   FilterEdit.InvalidateFilter;            // Data is shown by FilterEdit.
diff --git a/ide/searchfrm.pas b/ide/searchfrm.pas
index b725f87bfe..b894ce1f39 100644
--- a/ide/searchfrm.pas
+++ b/ide/searchfrm.pas
@@ -41,7 +41,7 @@ uses
   FileUtil, LazFileUtils, LazFileCache, LazTracer, LazUTF8,
   // IDEIntf
   IdeIntfStrConsts, IDEWindowIntf, LazIDEIntf, SrcEditorIntf, IDEDialogs,
-  ProjectGroupIntf, InputHistory,
+  ProjectGroupIntf, ProjectIntf, InputHistory,
   // IdeUtils
   IdeUtilsPkgStrConsts,
   // IdeConfig
@@ -1064,13 +1064,11 @@ var
 begin
   try
     TheFileList:= TStringList.Create;
-    AnUnitInfo:=AProject.FirstPartOfProject;
-    while AnUnitInfo<>nil do begin
+    for TLazProjectFile(AnUnitInfo) in AProject.UnitsBelongingToProject do begin
       //Only if file exists on disk.
       if FilenameIsAbsolute(AnUnitInfo.FileName)
       and FileExistsCached(AnUnitInfo.FileName) then
         TheFileList.Add(AnUnitInfo.FileName);
-      AnUnitInfo:=AnUnitInfo.NextPartOfProject;
     end;
     SearchFileList:= TheFileList;
     DoSearchAndAddToSearchResults;
diff --git a/ide/sourcefilemanager.pas b/ide/sourcefilemanager.pas
index 0d6373a091..6a8877320b 100644
--- a/ide/sourcefilemanager.pas
+++ b/ide/sourcefilemanager.pas
@@ -1871,8 +1871,7 @@ begin
     end;
 
     // removed directories still used for ObsoleteUnitPaths, ObsoleteIncPaths
-    AnUnitInfo:=Project1.FirstPartOfProject;
-    while AnUnitInfo<>nil do begin
+    for TLazProjectFile(AnUnitInfo) in Project1.UnitsBelongingToProject do begin
       if FilenameIsAbsolute(AnUnitInfo.Filename) then begin
         UnitPath:=ChompPathDelim(ExtractFilePath(AnUnitInfo.Filename));
         if FilenameIsPascalUnit(AnUnitInfo.Filename) then
@@ -1880,7 +1879,6 @@ begin
         if FilenameExtIs(AnUnitInfo.Filename,'inc') then
           ObsoleteIncPaths:=RemoveSearchPaths(ObsoleteIncPaths,UnitPath);
       end;
-      AnUnitInfo:=AnUnitInfo.NextPartOfProject;
     end;
 
     // check if compiler options contain paths of ObsoleteUnitPaths
@@ -3544,12 +3542,9 @@ begin
       end;
       if (fuooListed in Flags) then begin
         // add listed units (i.e. units in project inspector)
-        AnUnitInfo:=aProject.FirstPartOfProject;
-        while AnUnitInfo<>nil do
-        begin
+        for TLazProjectFile(AnUnitInfo) in aProject.UnitsBelongingToProject do begin
           if FilenameIsPascalUnit(AnUnitInfo.Filename) then
             Add(AnUnitInfo.Filename);
-          AnUnitInfo:=AnUnitInfo.NextPartOfProject;
         end;
       end;
       if (fuooListed in Flags) and (fuooPackages in Flags) then
@@ -4334,8 +4329,7 @@ begin
       DebugLn(['SaveProject - unit not found for page ',i,' File="',SrcEdit.FileName,'" SrcEdit=',dbgsname(SrcEdit),'=',dbgs(Pointer(SrcEdit))]);
       DumpStack;
       debugln(['SaveProject Project1 has the following information about the source editor:']);
-      AnUnitInfo:=Project1.FirstUnitWithEditorIndex;
-      while AnUnitInfo<>nil do begin
+      for TLazProjectFile(AnUnitInfo) in Project1.UnitsWithEditorIndex do begin
         for j:=0 to AnUnitInfo.EditorInfoCount-1 do begin
           dbgout(['  ',AnUnitInfo.Filename,' ',j,'/',AnUnitInfo.EditorInfoCount,' Component=',dbgsname(AnUnitInfo.EditorInfo[j].EditorComponent),'=',dbgs(Pointer(AnUnitInfo.EditorInfo[j].EditorComponent))]);
           if AnUnitInfo.EditorInfo[j].EditorComponent<>nil then
@@ -4343,7 +4337,6 @@ begin
           debugln;
         end;
         debugln(['  ',AnUnitInfo.EditorInfoCount]);
-        AnUnitInfo:=AnUnitInfo.NextUnitWithEditorIndex;
       end;
     end else begin
       if AnUnitInfo.IsVirtual then begin
@@ -7695,9 +7688,8 @@ function CloseUnitComponent(AnUnitInfo: TUnitInfo; Flags: TCloseFlags): TModalRe
   var
     CompUnitInfo: TUnitInfo;
   begin
-    CompUnitInfo:=Project1.FirstUnitWithComponent;
     Project1.UpdateUnitComponentDependencies;
-    while CompUnitInfo<>nil do begin
+    for TLazProjectFile(CompUnitInfo) in Project1.UnitsWithComponent do begin
       //DebugLn(['FreeUnusedComponents ',CompUnitInfo.Filename,' ',dbgsName(CompUnitInfo.Component),' UnitComponentIsUsed=',UnitComponentIsUsed(CompUnitInfo,true)]);
       if not UnitComponentIsUsed(CompUnitInfo,true) then begin
         // close the unit component
@@ -7705,7 +7697,6 @@ function CloseUnitComponent(AnUnitInfo: TUnitInfo; Flags: TCloseFlags): TModalRe
         // this has recursively freed all components, so exit here
         exit;
       end;
-      CompUnitInfo:=CompUnitInfo.NextUnitWithComponent;
     end;
   end;
 
@@ -8121,8 +8112,7 @@ var
   AnUnitInfo: TUnitInfo;
   LFMFilename: String;
 begin
-  AnUnitInfo:=Project1.FirstPartOfProject;
-  while AnUnitInfo<>nil do begin
+  for TLazProjectFile(AnUnitInfo) in Project1.UnitsBelongingToProject do begin
     if (not AnUnitInfo.HasResources)
     and (not AnUnitInfo.IsVirtual) and FilenameHasPascalExt(AnUnitInfo.Filename)
     then begin
@@ -8131,7 +8121,6 @@ begin
         LFMFilename:=ChangeFileExt(AnUnitInfo.Filename,'.dfm');
       AnUnitInfo.HasResources:=FileExistsCached(LFMFilename);
     end;
-    AnUnitInfo:=AnUnitInfo.NextPartOfProject;
   end;
 end;
 
diff --git a/ide/useunitdlg.pas b/ide/useunitdlg.pas
index a969b37be7..957711285d 100644
--- a/ide/useunitdlg.pas
+++ b/ide/useunitdlg.pas
@@ -382,15 +382,13 @@ begin
   else
     CurrentUnitName := '';
   // Add available unit names to list
-  ProjFile:=Project1.FirstPartOfProject;
-  while ProjFile <> nil do begin
+  for TLazProjectFile(ProjFile) in Project1.UnitsBelongingToProject do begin
     s := ProjFile.Unit_Name;
     if s = CurrentUnitName then       // current unit
       s := '';
     if (ProjFile <> Project1.MainUnitInfo) and (s <> '') then
       if not FMainUsedUnits.Find(s, x) then
         FProjUnits.AddObject(s, ProjFile);
-    ProjFile := ProjFile.NextPartOfProject;
   end;
   FProjUnits.Sorted := True;
 end;
diff --git a/packager/pkgmanager.pas b/packager/pkgmanager.pas
index 92a5cca92e..6dab0b1093 100644
--- a/packager/pkgmanager.pas
+++ b/packager/pkgmanager.pas
@@ -4754,11 +4754,9 @@ begin
       end;
     end else if CurOwner is TProject then begin
       CurProject:=TProject(CurOwner);
-      CurUnit:=CurProject.FirstPartOfProject;
-      while CurUnit<>nil do begin
+      for TLazProjectFile(CurUnit) in CurProject.UnitsBelongingToProject do begin
         if FilenameIsPascalSource(CurUnit.Filename) then
           AddFile(CurOwner,CurUnit.Filename);
-        CurUnit:=CurUnit.NextPartOfProject;
       end;
     end;
   end;
@@ -6341,10 +6339,8 @@ begin
   FMainUnitInfoValid:=false;
   if (MainOwner=nil) or (MainUnitInfo=nil) then exit;
   // search all open designer forms (can be hidden)
-  AnUnitInfo:=Project1.FirstUnitWithComponent;
-  while AnUnitInfo<>nil do begin
+  for TLazProjectFile(AnUnitInfo) in Project1.UnitsWithComponent do begin
     CheckUnit(AnUnitInfo);
-    AnUnitInfo:=AnUnitInfo.NextUnitWithComponent;
   end;
 end;