51
fCTLink: TCodeToolLink; // Link to codetools.
52
fUsesSection: TUsesSection; // Enum used by some codetools funcs.
53
fExistingUnits: TStringList; // List of units before conversion.
54
fUnitsToAddForLCL: TStringList; // List of new units for LCL (not for Delphi).
55
fUnitsToRemove: TStringList; // List of units to remove.
56
// Units to rename. Map old unit name -> new unit name.
57
fUnitsToRename: TStringToStringTree;
58
fUnitsToComment: TStringList; // List of units to be commented.
59
fMissingUnits: TStringList; // Units not found in search path.
51
fCTLink: TCodeToolLink; // Link to codetools.
52
fOwnerTool: TUsedUnitsTool;
53
fUsesSection: TUsesSection; // Enum used by some codetools funcs.
54
fExistingUnits: TStringList; // List of units before conversion.
55
fUnitsToAdd: TStringList; // List of new units to add.
56
fUnitsToAddForLCL: TStringList; // List of new units for LCL (not for Delphi).
57
fUnitsToRemove: TStringList; // List of units to remove.
58
fUnitsToRename: TStringToStringTree; // Units to rename. Map old name -> new name.
59
fUnitsToRenameKeys: TStringList; // List of keys of the above map.
60
fUnitsToRenameVals: TStringList; // List of values of the above map.
61
fUnitsToFixCase: TStringToStringTree;// Like rename but done for every target.
62
fUnitsToComment: TStringList; // List of units to be commented.
63
fMissingUnits: TStringList; // Units not found in search path.
64
function FindMissingUnits(AUnitUpdater: TStringMapUpdater): boolean;
60
65
procedure ToBeRenamedOrRemoved(AOldName, ANewName: string);
61
66
procedure FindReplacement(AUnitUpdater: TStringMapUpdater;
62
67
AMapToEdit: TStringToStringTree);
63
68
function AddDelphiAndLCLSections: Boolean;
64
69
function RemoveUnits: boolean;
65
function RenameUnits: boolean;
66
function AddUnits: boolean;
67
function CommentOutUnits: boolean;
69
71
// This is either the Interface or Implementation node.
70
72
function ParentBlockNode: TCodeTreeNode; virtual; abstract;
71
73
// Uses node in either Main or Implementation section.
72
74
function UsesSectionNode: TCodeTreeNode; virtual; abstract;
74
constructor Create(ACTLink: TCodeToolLink);
76
constructor Create(ACTLink: TCodeToolLink; aOwnerTool: TUsedUnitsTool);
75
77
destructor Destroy; override;
76
78
procedure CommentAutomatic(ACommentedUnits: TStringList);
78
property ExistingUnits: TStringList read fExistingUnits;
79
property UnitsToAddForLCL: TStringList read fUnitsToAddForLCL;
80
property MissingUnits: TStringList read fMissingUnits;
81
80
property UnitsToRemove: TStringList read fUnitsToRemove;
82
81
property UnitsToRename: TStringToStringTree read fUnitsToRename;
83
property UnitsToComment: TStringList read fUnitsToComment;
82
property UnitsToFixCase: TStringToStringTree read fUnitsToFixCase;
83
property MissingUnits: TStringList read fMissingUnits;
112
112
TUsedUnitsTool = class
114
114
fCTLink: TCodeToolLink;
116
fIsMainFile: Boolean; // Main project / package file.
117
fIsConsoleApp: Boolean;
115
118
fMainUsedUnits: TUsedUnits;
116
119
fImplUsedUnits: TUsedUnits;
120
fCheckPackageDependencyEvent: TCheckUnitEvent;
118
121
function GetMissingUnitCount: integer;
119
function GetMissingUnits: TModalResult;
121
123
constructor Create(ACTLink: TCodeToolLink; AFilename: string);
122
124
destructor Destroy; override;
123
125
function Prepare: TModalResult;
124
126
function Convert: TModalResult;
127
function Remove(AUnit: string): TModalResult;
125
128
procedure MoveMissingToComment(AAllCommentedUnits: TStrings);
129
procedure AddUnitIfNeeded(AUnitName: string);
130
function AddThreadSupport: TModalResult;
132
property IsMainFile: Boolean read fIsMainFile write fIsMainFile;
133
property IsConsoleApp: Boolean read fIsConsoleApp write fIsConsoleApp;
127
134
property MainUsedUnits: TUsedUnits read fMainUsedUnits;
128
135
property ImplUsedUnits: TUsedUnits read fImplUsedUnits;
129
136
property MissingUnitCount: integer read GetMissingUnitCount;
137
property CheckPackDepEvent: TCheckUnitEvent read fCheckPackageDependencyEvent
138
write fCheckPackageDependencyEvent;
174
190
fExistingUnits.Free;
175
191
fMissingUnits.Free;
176
192
fUnitsToComment.Free;
193
fUnitsToFixCase.Free;
194
fUnitsToRenameVals.Free;
195
fUnitsToRenameKeys.Free;
177
196
fUnitsToRename.Free;
178
197
fUnitsToRemove.Free;
179
198
fUnitsToAddForLCL.Free;
180
200
inherited Destroy;
183
// function TUsedUnits.GetMissingUnits: TModalResult; was here.
203
function TUsedUnits.FindMissingUnits(AUnitUpdater: TStringMapUpdater): boolean;
205
UsesNode: TCodeTreeNode;
206
InAtom, UnitNameAtom: TAtomPosition;
207
OldUnitName, OldInFilename: String;
208
NewUnitName, NewInFilename: String;
209
AFilename, s, slo: String;
213
UsesNode:=UsesSectionNode;
214
if UsesNode=nil then exit(true);
215
with fCTLink do begin
216
CodeTool.MoveCursorToUsesStart(UsesNode);
218
// read next unit name
219
CodeTool.ReadNextUsedUnit(UnitNameAtom, InAtom);
220
OldUnitName:=CodeTool.GetAtom(UnitNameAtom);
221
if InAtom.StartPos>0 then
222
OldInFilename:=copy(CodeTool.Src,InAtom.StartPos+1,
223
InAtom.EndPos-InAtom.StartPos-2)
227
NewUnitName:=OldUnitName;
228
NewInFilename:=OldInFilename;
229
AFilename:=CodeTool.FindUnitCaseInsensitive(NewUnitName,NewInFilename);
231
if NewInFilename<>'' then
232
s:=s+' in '''+NewInFilename+'''';
233
if AFilename<>'' then begin // unit found
234
OmitUnit:=Settings.OmitProjUnits.Find(NewUnitName, x);
235
if (NewUnitName<>OldUnitName) and not OmitUnit then begin
236
// Character case differs and it will not be replaced.
237
fUnitsToFixCase[OldUnitName]:=NewUnitName; // fix case
238
IDEMessagesWindow.AddMsg(Format(lisConvDelphiFixedUnitCase,
239
[OldUnitName, NewUnitName]), '', -1);
241
// Report Windows specific units as missing if target is MultiPlatform,
242
// needed if work-platform is Windows (kind of a hack).
243
slo:=LowerCase(NewUnitName); // 'variants' ?
244
if (Settings.MultiPlatform and ((slo='windows') or (slo='shellapi'))) or OmitUnit then
245
fMissingUnits.Add(s);
248
// Omit Windows specific units from the list if target is "Windows only",
249
// needed if work-platform is different from Windows (kind of a hack).
250
slo:=LowerCase(NewUnitName);
251
if Settings.MultiPlatform or ((slo<>'windows') and (slo<>'shellapi')) then
252
fMissingUnits.Add(s);
254
if CodeTool.CurPos.Flag=cafComma then begin
255
// read next unit name
256
CodeTool.ReadNextAtom;
257
end else if CodeTool.CurPos.Flag=cafSemicolon then begin
260
CodeTool.RaiseExceptionFmt(ctsStrExpectedButAtomFound,[';',CodeTool.GetAtom]);
185
266
procedure TUsedUnits.ToBeRenamedOrRemoved(AOldName, ANewName: string);
186
267
// Replace a unit name with a new name or remove it if there is no new name.
269
UnitInFileName: string;
188
271
if ANewName<>'' then begin
189
272
fUnitsToRename[AOldName]:=ANewName;
190
IDEMessagesWindow.AddMsg(Format(
191
lisConvDelphiReplacedUnitSWithSInUsesSection, [AOldName, ANewName]), '', -1);
273
fUnitsToRenameKeys.Add(AOldName);
274
fUnitsToRenameVals.Add(ANewName);
275
IDEMessagesWindow.AddMsg(Format(lisConvDelphiReplacedUnitInUsesSection,
276
[AOldName, ANewName]), '', -1);
277
// If the unit is not found, open the package containing it.
279
if fCTLink.CodeTool.FindUnitCaseInsensitive(ANewName,UnitInFileName) = '' then
280
if Assigned(fOwnerTool.CheckPackDepEvent) then
281
if not fOwnerTool.CheckPackDepEvent(ANewName) then
194
285
fUnitsToRemove.Add(AOldName);
195
IDEMessagesWindow.AddMsg(Format(
196
lisConvDelphiRemovedUsedUnitSInUsesSection, [AOldName]), '', -1);
286
IDEMessagesWindow.AddMsg(Format(lisConvDelphiRemovedUnitInUsesSection,
287
[AOldName]), '', -1);
223
314
DelphiOnlyUnits: TStringList; // Delphi specific units.
224
315
LclOnlyUnits: TStringList; // LCL specific units.
226
function MoveToDelphi(AUnitName: string; ARenameForLcl: boolean): boolean;
317
function MoveToDelphi(AUnitName: string): boolean;
228
319
UsesNode: TCodeTreeNode;
231
// if fExistingUnits.Find(AUnitName, ind) then begin
232
fCTLink.ResetMainScanner;
233
fCTLink.CodeTool.BuildTree(fUsesSection=usMain);
234
// Calls either FindMainUsesSection; or FindImplementationUsesSection;
322
with fCTLink do begin
324
if fUsesSection=usMain then
325
CodeTool.BuildTree(lsrMainUsesSectionEnd)
327
CodeTool.BuildTree(lsrImplementationUsesSectionEnd);
328
// Calls either FindMainUsesSection or FindImplementationUsesSection
235
329
UsesNode:=UsesSectionNode;
236
330
Assert(Assigned(UsesNode),
237
331
'UsesNode should be assigned in AddDelphiAndLCLSections->MoveToDelphi');
238
Result:=fCTLink.CodeTool.RemoveUnitFromUsesSection(UsesNode,
239
UpperCaseStr(AUnitName), fCTLink.SrcCache);
240
DelphiOnlyUnits.Add(AUnitName);
241
if ARenameForLcl then
242
LCLOnlyUnits.Add(fUnitsToRename[AUnitName]);
332
Result:=CodeTool.RemoveUnitFromUsesSection(UsesNode,UpperCaseStr(AUnitName),SrcCache);
334
DelphiOnlyUnits.Add(AUnitName);
247
338
i, InsPos: Integer;
250
RenameList: TStringList;
251
341
UsesNode: TCodeTreeNode;
252
342
ParentBlock: TCodeTreeNode;
255
345
DelphiOnlyUnits:=TStringList.Create;
256
346
LclOnlyUnits:=TStringList.Create;
257
RenameList:=TStringList.Create;
259
348
// Don't remove the unit names but add to Delphi block instead.
260
349
for i:=0 to fUnitsToRemove.Count-1 do
261
if not MoveToDelphi(fUnitsToRemove[i], False) then Exit;
350
if not MoveToDelphi(fUnitsToRemove[i]) then Exit;
262
351
// ... and don't comment the unit names either.
263
352
for i:=0 to fUnitsToComment.Count-1 do
264
if not MoveToDelphi(fUnitsToComment[i], False) then Exit;
353
if not MoveToDelphi(fUnitsToComment[i]) then Exit;
265
354
// Add replacement units to LCL block.
266
fUnitsToRename.GetNames(RenameList);
267
for i:=0 to RenameList.Count-1 do
268
if not MoveToDelphi(RenameList[i], True) then Exit;
355
for i:=0 to fUnitsToRenameKeys.Count-1 do begin
356
if not MoveToDelphi(fUnitsToRenameKeys[i]) then Exit;
357
LCLOnlyUnits.Add(fUnitsToRename[fUnitsToRenameKeys[i]]);
269
359
// Additional units for LCL (like Interfaces).
270
360
LCLOnlyUnits.AddStrings(fUnitsToAddForLCL);
271
361
// Add LCL and Delphi sections for output.
272
362
if (LclOnlyUnits.Count=0) and (DelphiOnlyUnits.Count=0) then Exit(True);
273
363
fCTLink.ResetMainScanner;
274
fCTLink.CodeTool.BuildTree(fUsesSection=usMain);
364
if fUsesSection=usMain then
365
fCTLink.CodeTool.BuildTree(lsrMainUsesSectionEnd)
367
fCTLink.CodeTool.BuildTree(lsrImplementationUsesSectionEnd);
275
368
UsesNode:=UsesSectionNode;
276
if Assigned(UsesNode) then begin //uses section exists
369
if Assigned(UsesNode) then begin //uses section exists
279
//TODO: check for special units
280
372
fCTLink.CodeTool.MoveCursorToUsesStart(UsesNode);
281
373
InsPos:=fCTLink.CodeTool.CurPos.StartPos;
283
else begin //uses section does not exist
375
else begin //uses section does not exist
286
378
// ParentBlock should never be Nil. UsesNode=Nil only for implementation section.
342
434
for i:=0 to fUnitsToRemove.Count-1 do begin
343
435
fCTLink.ResetMainScanner;
344
fCTLink.CodeTool.BuildTree(fUsesSection=usMain);
436
if fUsesSection=usMain then
437
fCTLink.CodeTool.BuildTree(lsrMainUsesSectionEnd)
439
fCTLink.CodeTool.BuildTree(lsrImplementationUsesSectionEnd);
345
440
if not fCTLink.CodeTool.RemoveUnitFromUsesSection(UsesSectionNode,
346
441
UpperCaseStr(fUnitsToRemove[i]), fCTLink.SrcCache) then
348
443
if not fCTLink.SrcCache.Apply then exit;
350
//fUnitsToRemove.Clear;
354
function TUsedUnits.RenameUnits: boolean;
358
if not fCTLink.CodeTool.ReplaceUsedUnits(fUnitsToRename, fCTLink.SrcCache) then
360
//fUnitsToRename.Clear;
364
function TUsedUnits.AddUnits: boolean;
369
for i:=0 to fUnitsToAddForLCL.Count-1 do
370
if not fCTLink.CodeTool.AddUnitToSpecificUsesSection(
371
fUsesSection, fUnitsToAddForLCL[i], '', fCTLink.SrcCache) then exit;
375
function TUsedUnits.CommentOutUnits: boolean;
376
// Comment out missing units
379
if fUnitsToComment.Count>0 then
380
if not fCTLink.CodeTool.CommentUnitsInUsesSections(fUnitsToComment,
381
fCTLink.SrcCache) then
445
fUnitsToRemove.Clear;
386
449
{ TMainUsedUnits }
388
constructor TMainUsedUnits.Create(ACTLink: TCodeToolLink);
451
constructor TMainUsedUnits.Create(ACTLink: TCodeToolLink; aOwnerTool: TUsedUnitsTool);
390
inherited Create(ACTLink);
453
inherited Create(ACTLink, aOwnerTool);
391
454
fUsesSection:=usMain;
449
514
inherited Destroy;
452
function TUsedUnitsTool.GetMissingUnits: TModalResult;
453
// Get missing unit by codetools.
454
// This can be moved to TUsedUnits if codetools is refactored.
458
AllMissUnits: TStrings;
461
AllMissUnits:=nil; // Will be created by FindMissingUnits.
463
if not fCTLink.CodeTool.FindMissingUnits(AllMissUnits,False,True,fCTLink.SrcCache)
468
if Assigned(AllMissUnits) then begin
469
// Remove Windows specific units from the list if target is "Windows only",
470
// needed if work-platform is different from Windows (kind of a hack).
471
if fCTLink.Settings.Target=ctLazarusWin then begin
472
for i:=AllMissUnits.Count-1 downto 0 do begin
473
s:=LowerCase(AllMissUnits[i]);
474
if (s='windows') or (s='variants') or (s='shellapi') then
475
AllMissUnits.Delete(i);
478
// Split AllMissUnits into Main and Implementation
479
for i:=0 to AllMissUnits.Count-1 do begin
481
if fMainUsedUnits.ExistingUnits.IndexOf(s)<>-1 then
482
fMainUsedUnits.MissingUnits.Add(s);
483
if fImplUsedUnits.ExistingUnits.IndexOf(s)<>-1 then
484
fImplUsedUnits.MissingUnits.Add(s);
492
517
function TUsedUnitsTool.Prepare: TModalResult;
493
518
// Find missing units and mark some of them to be replaced later.
494
519
// More units can be marked for add, remove, rename and comment during conversion.
547
576
function TUsedUnitsTool.Convert: TModalResult;
548
577
// Add, remove, rename and comment out unit names that were marked earlier.
550
581
Result:=mrCancel;
551
if fCTLink.Settings.Target=ctLazarus then begin
552
// One way conversion -> remove and rename units.
553
if not fMainUsedUnits.RemoveUnits then exit; // Remove
554
if not fImplUsedUnits.RemoveUnits then exit;
555
if not fMainUsedUnits.RenameUnits then exit; // Rename
556
if not fImplUsedUnits.RenameUnits then exit;
582
with fCTLink do begin
584
if not CodeTool.ReplaceUsedUnits(fMainUsedUnits.fUnitsToFixCase, SrcCache) then exit;
585
if not CodeTool.ReplaceUsedUnits(fImplUsedUnits.fUnitsToFixCase, SrcCache) then exit;
587
with fMainUsedUnits do begin
588
for i:=0 to fUnitsToAdd.Count-1 do
589
if not CodeTool.AddUnitToSpecificUsesSection(
590
fUsesSection, fUnitsToAdd[i], '', SrcCache) then exit;
592
with fImplUsedUnits do begin
593
for i:=0 to fUnitsToAdd.Count-1 do
594
if not CodeTool.AddUnitToSpecificUsesSection(
595
fUsesSection, fUnitsToAdd[i], '', SrcCache) then exit;
597
if fIsMainFile or (Settings.MultiPlatform and not Settings.SupportDelphi) then begin
598
// One way conversion (or main file) -> remove and rename units.
599
if not fMainUsedUnits.RemoveUnits then exit; // Remove
600
if not fImplUsedUnits.RemoveUnits then exit;
602
if not CodeTool.ReplaceUsedUnits(fMainUsedUnits.fUnitsToRename, SrcCache) then exit;
603
if not CodeTool.ReplaceUsedUnits(fImplUsedUnits.fUnitsToRename, SrcCache) then exit;
605
if Settings.SupportDelphi then begin
606
// Support Delphi. Add IFDEF blocks for units.
607
if not fMainUsedUnits.AddDelphiAndLCLSections then exit;
608
if not fImplUsedUnits.AddDelphiAndLCLSections then exit;
610
else begin // Lazarus only multi- or single-platform -> comment out units if needed.
611
if not CodeTool.CommentUnitsInUsesSections(fMainUsedUnits.fUnitsToComment,
613
if not CodeTool.CommentUnitsInUsesSections(fImplUsedUnits.fUnitsToComment,
615
// Add more units meant for only LCL.
616
with fMainUsedUnits do begin
617
for i:=0 to fUnitsToAddForLCL.Count-1 do
618
if not CodeTool.AddUnitToSpecificUsesSection(
619
fUsesSection, fUnitsToAddForLCL[i], '', SrcCache) then exit;
621
with fImplUsedUnits do begin
622
for i:=0 to fUnitsToAddForLCL.Count-1 do
623
if not CodeTool.AddUnitToSpecificUsesSection(
624
fUsesSection, fUnitsToAddForLCL[i], '', SrcCache) then exit;
558
if fCTLink.Settings.Target in [ctLazarusDelphi, ctLazarusDelphiSameDfm] then begin
559
// Support Delphi. Add IFDEF blocks for units.
560
if not fMainUsedUnits.AddDelphiAndLCLSections then exit;
561
if not fImplUsedUnits.AddDelphiAndLCLSections then exit;
631
function TUsedUnitsTool.Remove(AUnit: string): TModalResult;
636
if fMainUsedUnits.fExistingUnits.Find(AUnit, x) then begin
637
fMainUsedUnits.UnitsToRemove.Add(AUnit);
563
else begin // [ctLazarus, ctLazarusWin] -> comment out units if needed.
564
if not fMainUsedUnits.CommentOutUnits then exit;
565
if not fImplUsedUnits.CommentOutUnits then exit;
566
if not fMainUsedUnits.AddUnits then exit; // Add the extra units.
567
if not fImplUsedUnits.AddUnits then exit;
640
else if fImplUsedUnits.fExistingUnits.Find(AUnit, x) then begin
641
fImplUsedUnits.UnitsToRemove.Add(AUnit);
572
646
procedure TUsedUnitsTool.MoveMissingToComment(AAllCommentedUnits: TStrings);
574
648
// These units will be commented automatically in one project/package.
575
649
if Assigned(AAllCommentedUnits) then begin
576
AAllCommentedUnits.AddStrings(fMainUsedUnits.MissingUnits);
577
AAllCommentedUnits.AddStrings(fImplUsedUnits.MissingUnits);
650
AAllCommentedUnits.AddStrings(fMainUsedUnits.fMissingUnits);
651
AAllCommentedUnits.AddStrings(fImplUsedUnits.fMissingUnits);
579
653
// Move all to be commented.
580
fMainUsedUnits.UnitsToComment.AddStrings(fMainUsedUnits.MissingUnits);
581
fMainUsedUnits.MissingUnits.Clear;
582
fImplUsedUnits.UnitsToComment.AddStrings(fImplUsedUnits.MissingUnits);
583
fImplUsedUnits.MissingUnits.Clear;
654
fMainUsedUnits.fUnitsToComment.AddStrings(fMainUsedUnits.fMissingUnits);
655
fMainUsedUnits.fMissingUnits.Clear;
656
fImplUsedUnits.fUnitsToComment.AddStrings(fImplUsedUnits.fMissingUnits);
657
fImplUsedUnits.fMissingUnits.Clear;
660
procedure TUsedUnitsTool.AddUnitIfNeeded(AUnitName: string);
663
UnitInFileName: String;
664
RenameValFound: Boolean;
666
RenameValFound:=false;
667
for i := 0 to fMainUsedUnits.fUnitsToRenameVals.Count-1 do
668
if Pos(AUnitName, fMainUsedUnits.fUnitsToRenameVals[i]) > 0 then begin
669
RenameValFound:=true;
672
if not RenameValFound then
673
for i := 0 to fImplUsedUnits.fUnitsToRenameVals.Count-1 do
674
if Pos(AUnitName, fImplUsedUnits.fUnitsToRenameVals[i]) > 0 then begin
675
RenameValFound:=true;
678
if not ( fMainUsedUnits.fExistingUnits.Find(AUnitName, i) or
679
fImplUsedUnits.fExistingUnits.Find(AUnitName, i) or
680
(fMainUsedUnits.fUnitsToAdd.IndexOf(AUnitName) > -1) or RenameValFound)
682
fMainUsedUnits.fUnitsToAdd.Add(AUnitName);
683
IDEMessagesWindow.AddMsg('Added unit '+AUnitName+ ' to uses section', '', -1);
684
// If the unit is not found, open the package containing it.
686
if fCTLink.CodeTool.FindUnitCaseInsensitive(AUnitName,UnitInFileName) = '' then
687
if Assigned(fCheckPackageDependencyEvent) then
688
if not fCheckPackageDependencyEvent(AUnitName) then
693
function TUsedUnitsTool.AddThreadSupport: TModalResult;
694
// AddUnitToSpecificUsesSection would insert cthreads in the beginning automatically
695
// It doesn't work with {$IFDEF UNIX} directive -> use UsesInsertPolicy.
698
OldPolicy: TUsesInsertPolicy;
701
if not ( fMainUsedUnits.fExistingUnits.Find('cthreads', i) or
702
fImplUsedUnits.fExistingUnits.Find('cthreads', i) ) then
703
with fCTLink, SrcCache.BeautifyCodeOptions do
705
OldPolicy:=UsesInsertPolicy;
706
UsesInsertPolicy:=uipFirst;
707
if not CodeTool.AddUnitToSpecificUsesSection(fMainUsedUnits.fUsesSection,
708
'{$IFDEF UNIX}cthreads{$ENDIF}', '', SrcCache) then exit;
710
UsesInsertPolicy:=OldPolicy;
586
715
function TUsedUnitsTool.GetMissingUnitCount: integer;
588
Result:=fMainUsedUnits.MissingUnits.Count+fImplUsedUnits.MissingUnits.Count;
717
Result:=fMainUsedUnits.fMissingUnits.Count+fImplUsedUnits.fMissingUnits.Count;