diff --git a/converter/convcodetool.pas b/converter/convcodetool.pas index 4be20ad610..46c7488e9b 100644 --- a/converter/convcodetool.pas +++ b/converter/convcodetool.pas @@ -41,20 +41,18 @@ type fUnitsToRename: TStringToStringTree; // List of units to be commented. fUnitsToComment: TStringList; - // Map of class member object types to be renamed in ReplaceMemberTypes. - fMemberTypesToRename: TStringToStringTree; function AddDelphiAndLCLSections: boolean; function AddModeDelphiDirective: boolean; function RenameResourceDirectives: boolean; - function RemoveUnits: boolean; - function RenameUnits: boolean; function CommentOutUnits: boolean; function HandleCodetoolError: TModalResult; public constructor Create(Code: TCodeBuffer); destructor Destroy; override; function Convert: TModalResult; - function ReplaceMemberTypes(AClassName: string): boolean; + function RemoveUnits: boolean; + function RenameUnits: boolean; + function UsesSectionsToUnitnames: TStringList; public property Ask: Boolean read fAsk write fAsk; property UseBothDfmAndLfm: boolean read fUseBothDfmAndLfm write fUseBothDfmAndLfm; @@ -64,8 +62,6 @@ type property UnitsToRemove: TStringList read fUnitsToRemove write fUnitsToRemove; property UnitsToRename: TStringToStringTree read fUnitsToRename write fUnitsToRename; property UnitsToComment: TStringList read fUnitsToComment write fUnitsToComment; - property MemberTypesToRename: TStringToStringTree read fMemberTypesToRename - write fMemberTypesToRename; end; implementation @@ -83,7 +79,6 @@ begin fUnitsToRemove:=nil; // These are set from outside. fUnitsToComment:=nil; fUnitsToRename:=nil; - fMemberTypesToRename:=nil; // Initialize codetools. (Copied from TCodeToolManager.) if not CodeToolBoss.InitCurCodeTool(fCode) then exit; try @@ -376,12 +371,20 @@ begin Result:=true; end; -function TConvDelphiCodeTool.ReplaceMemberTypes(AClassName: string): boolean; -// Replace types of class object members. +function TConvDelphiCodeTool.UsesSectionsToUnitnames: TStringList; +// Collect all unit names from uses sections to a StringList. +var + UsesNode: TCodeTreeNode; + ImplList: TStrings; begin -// CodeToolBoss.RetypeClassVariables(); - Result:=fCodeTool.RetypeClassVariables(AClassName, fMemberTypesToRename, - false, fSrcCache); + fCodeTool.BuildTree(true); + fSrcCache.MainScanner:=fCodeTool.Scanner; + UsesNode:=fCodeTool.FindMainUsesSection; + Result:=TStringList(fCodeTool.UsesSectionToUnitnames(UsesNode)); + UsesNode:=fCodeTool.FindImplementationUsesSection; + ImplList:=fCodeTool.UsesSectionToUnitnames(UsesNode); + Result.AddStrings(ImplList); + ImplList.Free; end; diff --git a/converter/convertdelphi.pas b/converter/convertdelphi.pas index 6f8a361fae..cdb6732790 100644 --- a/converter/convertdelphi.pas +++ b/converter/convertdelphi.pas @@ -43,7 +43,7 @@ uses // IDE IDEProcs, Project, DialogProcs, EditorOptions, CompilerOptions, PackageDefs, PackageSystem, - PackageEditor, BasePkgManager, LazarusIDEStrConsts, + PackageEditor, BasePkgManager, LazarusIDEStrConsts, ReplaceNamesUnit, ConvertSettings, ConvCodeTool, MissingUnits, MissingPropertiesDlg; const @@ -590,7 +590,9 @@ begin finally LfmFixer.Free; end; - // save LFM file + // save source and LFM files + Result:=SaveCodeBufferToFile(fPascalBuffer,fPascalBuffer.Filename); + if Result<>mrOk then exit; Result:=SaveCodeBufferToFile(fLFMBuffer,fLFMBuffer.Filename); if Result<>mrOk then exit; end; @@ -715,18 +717,28 @@ end; function TConvertDelphiUnit.FixMissingUnits: TModalResult; var + UnitUpdater: TStringMapUpdater; + ConvTool: TConvDelphiCodeTool; + UnitNames: TStringList; CTResult: Boolean; - i: Integer; - UnitN, s: string; + i, d: Integer; + UnitN, FN, s: string; begin Result:=mrOk; + UnitUpdater:=TStringMapUpdater.Create(fSettings.ReplaceUnits); + ConvTool:=TConvDelphiCodeTool.Create(fPascalBuffer); + UnitNames:=nil; // Will be created in ConvTool.UsesSectionsToUnitnames. fMissingUnits:=nil; // Will be created in CodeToolBoss.FindMissingUnits. try + // Collect all unit names from uses sections. + UnitNames:=ConvTool.UsesSectionsToUnitnames; + UnitNames.Sorted:=true; + s:=UnitNames.Text; // find missing units CTResult:=CodeToolBoss.FindMissingUnits(fPascalBuffer,fMissingUnits,true); if not CTResult then begin IDEMessagesWindow.AddMsg('Error="'+CodeToolBoss.ErrorMessage+'"','',-1); - Application.ProcessMessages; + Result:=mrCancel; exit; end; // no missing units -> good @@ -735,9 +747,8 @@ begin // Remove or replace units defined in settings. for i:=fMissingUnits.Count-1 downto 0 do begin UnitN:=fMissingUnits[i]; - if fSettings.ReplaceUnits.Contains(UnitN) then begin - s:=fSettings.ReplaceUnits[UnitN]; - if s<>'' then begin + if UnitUpdater.FindReplacement(UnitN, s) then begin + if (s<>'') and not UnitNames.Find(s, d) then begin fUnitsToRename[UnitN]:=s; IDEMessagesWindow.AddMsg(Format( 'Replaced unit "%s" with "%s" in uses section.',[UnitN, s]),'',-1); @@ -747,9 +758,23 @@ begin IDEMessagesWindow.AddMsg(Format( 'Removed used unit "%s" in uses section.',[UnitN]),'',-1); end; - fMissingUnits.Delete(i); end; end; + // Remove and rename missing units. More of them may be added later. + ConvTool.UnitsToRename:=fUnitsToRename; + ConvTool.UnitsToRemove:=fUnitsToRemove; + ConvTool.RenameUnits; + ConvTool.RemoveUnits; + fUnitsToRename.Clear; + fUnitsToRemove.Clear; + // Find missing units again. Some replacements may not be valid. + fMissingUnits.Clear; + CTResult:=CodeToolBoss.FindMissingUnits(fPascalBuffer,fMissingUnits,true); + if not CTResult then begin + IDEMessagesWindow.AddMsg('Error="'+CodeToolBoss.ErrorMessage+'"','',-1); + Result:=mrCancel; + exit; + end; if fMissingUnits.Count=0 then exit; if Assigned(fOwnerConverter) then begin @@ -769,6 +794,9 @@ begin Application.ProcessMessages; finally fMissingUnits.Free; + UnitNames.Free; + ConvTool.Free; + UnitUpdater.Free; end; end; @@ -854,6 +882,7 @@ begin // load required packages AddPackageDependency('LCL');// Nearly all Delphi projects require it + AddPackageDependency('virtualtreeview_package'); //!!! if fProjPack is TProject then PkgBoss.AddDefaultDependencies(fProjPack as TProject); CustomDefinesChanged; diff --git a/converter/convertsettings.pas b/converter/convertsettings.pas index d18e19918b..15a95f563b 100644 --- a/converter/convertsettings.pas +++ b/converter/convertsettings.pas @@ -147,17 +147,10 @@ begin fReplaceUnits['Windows']:='LCLIntf, LCLType, LMessages'; fReplaceUnits['Variants']:=''; fReplaceUnits['ShellApi']:=''; - fReplaceUnits['TntActnList']:='ActnList'; - fReplaceUnits['TntMenus']:='Menus'; - fReplaceUnits['TntClasses']:='Classes'; - fReplaceUnits['TntForms']:='Forms'; - fReplaceUnits['TntComCtrls']:='ComCtrls'; - fReplaceUnits['TntStdCtrls']:='StdCtrls'; - fReplaceUnits['TntExtCtrls']:='ExtCtrls'; - fReplaceUnits['TntSysUtils']:='SysUtils'; fReplaceUnits['pngImage']:=''; fReplaceUnits['Jpeg']:=''; fReplaceUnits['gifimage']:=''; + fReplaceUnits['^Tnt(.+)']:='$1'; // Map Delphi types to LCL types. fReplaceTypes:=TStringToStringTree.Create(false); @@ -171,7 +164,7 @@ begin fReplaceTypes['TDBRichEdit']:='TDBMemo'; fReplaceTypes['TApplicationEvents']:='TApplicationProperties'; fReplaceTypes['TPNGObject']:='TPortableNetworkGraphic'; - fReplaceTypes['TTnt(.+)']:='T$1'; + fReplaceTypes['^TTnt(.+)']:='T$1'; end; @@ -354,31 +347,37 @@ end; procedure TConvertSettingsForm.UnitReplacementsButtonClick(Sender: TObject); var - ReplaceNamesForm: TReplaceNamesForm; + RNForm: TReplaceNamesForm; + GridUpdater: TGridUpdater; begin - ReplaceNamesForm:=TReplaceNamesForm.Create(nil); + RNForm:=TReplaceNamesForm.Create(nil); + GridUpdater:=TGridUpdater.Create(fSettings.ReplaceUnits, RNForm.NamePairGrid); try - ReplaceNamesForm.Caption:=lisConvUnitsToReplace; - CopyFromMapToGrid(ReplaceNamesForm.NamePairGrid, fSettings.ReplaceUnits); - if ReplaceNamesForm.ShowModal=mrOK then - CopyFromGridToMap(ReplaceNamesForm.NamePairGrid, fSettings.ReplaceUnits); + RNForm.Caption:=lisConvUnitsToReplace; + GridUpdater.MapToGrid; + if RNForm.ShowModal=mrOK then + GridUpdater.GridToMap; finally - ReplaceNamesForm.Free; + GridUpdater.Free; + RNForm.Free; end; end; procedure TConvertSettingsForm.TypeReplacementsButtonClick(Sender: TObject); var - ReplaceNamesForm: TReplaceNamesForm; + RNForm: TReplaceNamesForm; + GridUpdater: TGridUpdater; begin - ReplaceNamesForm:=TReplaceNamesForm.Create(nil); + RNForm:=TReplaceNamesForm.Create(nil); + GridUpdater:=TGridUpdater.Create(fSettings.ReplaceTypes, RNForm.NamePairGrid); try - ReplaceNamesForm.Caption:=lisConvTypesToReplace; - CopyFromMapToGrid(ReplaceNamesForm.NamePairGrid, fSettings.ReplaceTypes); - if ReplaceNamesForm.ShowModal=mrOK then - CopyFromGridToMap(ReplaceNamesForm.NamePairGrid, fSettings.ReplaceTypes); + RNForm.Caption:=lisConvTypesToReplace; + GridUpdater.MapToGrid; + if RNForm.ShowModal=mrOK then + GridUpdater.GridToMap; finally - ReplaceNamesForm.Free; + GridUpdater.Free; + RNForm.Free; end; end; diff --git a/converter/missingpropertiesdlg.pas b/converter/missingpropertiesdlg.pas index f896c8d607..c192f595b0 100644 --- a/converter/missingpropertiesdlg.pas +++ b/converter/missingpropertiesdlg.pas @@ -40,9 +40,9 @@ uses // codetools BasicCodeTools, CodeCache, CodeToolManager, CodeToolsStructs, // IDE - IDEDialogs, ComponentReg, PackageIntf, IDEWindowIntf, + IDEDialogs, ComponentReg, PackageIntf, IDEWindowIntf, DialogProcs, CustomFormEditor, LazarusIDEStrConsts, IDEProcs, OutputFilter, - EditorOptions, ConvertSettings, ConvCodeTool, ReplaceNamesUnit, CheckLFMDlg; + EditorOptions, ConvertSettings, ReplaceNamesUnit, CheckLFMDlg; type @@ -225,7 +225,6 @@ end; function TLFMFixer.ReplaceAndRemoveAll: TModalResult; var - ConvTool: TConvDelphiCodeTool; CurError: TLFMError; TheNode: TLFMTreeNode; ObjNode: TLFMObjectNode; @@ -233,15 +232,17 @@ var NameReplacements: TStringToStringTree; // List of TLFMChangeEntry objects. ChgEntryRepl: TObjectList; + GridUpdater: TGridUpdater; OldIdent, NewIdent: string; StartPos, EndPos: integer; begin - Result:=mrNone; + Result:=mrOK; ChgEntryRepl:=TObjectList.Create; NameReplacements:=TStringToStringTree.Create(false); + GridUpdater:=TGridUpdater.Create(NameReplacements, fPropReplaceGrid); try // Collect (maybe edited) properties from StringGrid to NameReplacements. - CopyFromGridToMap(fPropReplaceGrid, NameReplacements); + GridUpdater.GridToMap; // Replace each missing property / type or delete it if no replacement. CurError:=fLFMTree.LastError; while CurError<>nil do begin @@ -274,19 +275,18 @@ begin end; CurError:=CurError.PrevError; end; - // Apply replacements to LFM. - if ApplyReplacements(ChgEntryRepl) then begin - // Replace the object member types also to pascal source. - ConvTool:=TConvDelphiCodeTool.Create(fPascalBuffer); - try - ConvTool.MemberTypesToRename:=NameReplacements; - ConvTool.ReplaceMemberTypes(TLFMObjectNode(fLFMTree.Root).TypeName); - finally - ConvTool.Free; - end; - Result:=mrOk; + // Apply replacement types also to pascal source. + if not CodeToolBoss.RetypeClassVariables(fPascalBuffer, + TLFMObjectNode(fLFMTree.Root).TypeName, NameReplacements, false) + then begin + Result:=mrCancel; + exit; end; + // Apply replacements to LFM. + if not ApplyReplacements(ChgEntryRepl) then + Result:=mrCancel; finally + GridUpdater.Free; NameReplacements.Free; ChgEntryRepl.Free; end; @@ -299,7 +299,7 @@ var OldIdent: string; begin fHasMissingObjectTypes:=false; - GridUpdater:=TGridUpdater.Create(fPropReplaceGrid, fSettings.ReplaceTypes); + GridUpdater:=TGridUpdater.Create(fSettings.ReplaceTypes, fPropReplaceGrid); try if fLFMTree<>nil then begin CurError:=fLFMTree.FirstError; diff --git a/converter/replacenamesunit.pas b/converter/replacenamesunit.pas index 2316bdaf64..4caa519dda 100644 --- a/converter/replacenamesunit.pas +++ b/converter/replacenamesunit.pas @@ -10,20 +10,31 @@ uses type + { TStringMapUpdater } + + TStringMapUpdater = class + private + fStringMap: TStringToStringTree; + fMapNames: TStringList; // Names (keys) in fStringMap. + fSeenName: TStringList; + public + constructor Create(AStringMap: TStringToStringTree); + destructor Destroy; override; + function FindReplacement(AIdent: string; out AReplacement: string): boolean; + end; + { TGridUpdater } - TGridUpdater = class + TGridUpdater = class(TStringMapUpdater) private fGrid: TStringGrid; - fReplaceMap: TStringToStringTree; - fNameList: TStringList; // Names (keys) in fReplaceMap. - fSeenName: TStringList; GridEndInd: Integer; - function FindReplacement(AIdent: string): string; public - constructor Create(AGrid: TStringGrid; AReplaceMap: TStringToStringTree); + constructor Create(AStringMap: TStringToStringTree; AGrid: TStringGrid); destructor Destroy; override; procedure AddUnique(AOldIdent: string); + procedure MapToGrid; + procedure GridToMap; end; { TReplaceNamesForm } @@ -45,15 +56,81 @@ type var ReplaceNamesForm: TReplaceNamesForm; -procedure CopyFromMapToGrid(AGrid: TStringGrid; AMap: TStringToStringTree); -procedure CopyFromGridToMap(AGrid: TStringGrid; AMap: TStringToStringTree); - implementation {$R *.lfm} -procedure CopyFromMapToGrid(AGrid: TStringGrid; AMap: TStringToStringTree); +{ TStringMapUpdater } + +constructor TStringMapUpdater.Create(AStringMap: TStringToStringTree); +begin + fStringMap:=AStringMap; + fMapNames:=TStringList.Create; + fStringMap.GetNames(fMapNames); + fSeenName:=TStringList.Create; +end; + +destructor TStringMapUpdater.Destroy; +begin + fSeenName.Free; + fMapNames.Free; + inherited Destroy; +end; + +function TStringMapUpdater.FindReplacement(AIdent: string; + out AReplacement: string): boolean; +// Try to find a matching replacement using regular expression. +var + RE: TRegExpr; + i: Integer; + Key: string; +begin + if fStringMap.Contains(AIdent) then begin + AReplacement:=fStringMap[AIdent]; + Result:=true; + end + else begin // Not found by name, try regexp. + Result:=false; + AReplacement:=''; + RE:=TRegExpr.Create; + try + for i:=0 to fMapNames.Count-1 do begin + Key:=fMapNames[i]; // fMapNames has extracted keys from fStringMap. + // If key contains '(' assume it is a regexp. + if Pos('(', Key)>0 then begin + RE.Expression:=Key; + if RE.Exec(AIdent) then begin // Match with regexp. + AReplacement:=RE.Substitute(fStringMap[Key]); + Result:=true; + Break; + end; + end; + end; + finally + RE.Free; + end; + end; +end; + + +{ TGridUpdater } + +constructor TGridUpdater.Create(AStringMap: TStringToStringTree; AGrid: TStringGrid); +begin + inherited Create(AStringMap); + fGrid:=AGrid; + GridEndInd:=1; + fGrid.BeginUpdate; +end; + +destructor TGridUpdater.Destroy; +begin + fGrid.EndUpdate; + inherited Destroy; +end; + +procedure TGridUpdater.MapToGrid; var OldIdent, NewIdent: string; List: TStringList; @@ -62,80 +139,33 @@ begin // Collect (maybe edited) properties from StringGrid to NameReplacements. List:=TStringList.Create; try - AGrid.BeginUpdate; - AMap.GetNames(List); + fGrid.BeginUpdate; + fStringMap.GetNames(List); for i:=0 to List.Count-1 do begin OldIdent:=List[i]; - NewIdent:=AMap[OldIdent]; - if AGrid.RowCount'' then - AMap[OldIdent]:=NewIdent; - end; -end; - -{ TGridUpdater } - -constructor TGridUpdater.Create(AGrid: TStringGrid; AReplaceMap: TStringToStringTree); -begin - fGrid:=AGrid; - fReplaceMap:=AReplaceMap; - fNameList:=TStringList.Create; - fReplaceMap.GetNames(fNameList); - fSeenName:=TStringList.Create; - GridEndInd:=1; - fGrid.BeginUpdate; -end; - -destructor TGridUpdater.Destroy; -begin - fGrid.EndUpdate; - fSeenName.Free; - fNameList.Free; - inherited Destroy; -end; - -function TGridUpdater.FindReplacement(AIdent: string): string; -// Try to find a matching replacement using regular expression. -var - RE: TRegExpr; - i: Integer; - s: string; -begin - Result:=''; - RE:=TRegExpr.Create; - try - for i:=0 to fNameList.Count-1 do begin - s:=fNameList[i]; // NameList has extracted keys from fReplaceMap. - // If key contains '(' assume it is a regexp. - if Pos('(', s)>0 then begin - RE.Expression:=s; - if RE.Exec(AIdent) then begin // Match with regexp. - Result:=RE.Substitute(fReplaceMap[s]); - Break; - end; - end; - end; - finally - RE.Free; + fStringMap[OldIdent]:=NewIdent; end; end; @@ -147,9 +177,7 @@ begin // Add only one instance of each property name. if fSeenName.IndexOf(AOldIdent)<0 then begin fSeenName.Append(AOldIdent); - NewIdent:=fReplaceMap[AOldIdent]; - if NewIdent='' then // Not found by name, try regexp. - NewIdent:=FindReplacement(AOldIdent); + FindReplacement(AOldIdent, NewIdent); if fGrid.RowCount