Converter: improved function replacement with categories. Added more UTF8 functions.

git-svn-id: trunk@26720 -
This commit is contained in:
juha 2010-07-17 20:58:58 +00:00
parent 62d890f71d
commit 60d84c8bf0
5 changed files with 123 additions and 62 deletions

View File

@ -52,12 +52,12 @@ type
function CommentOutUnits: boolean;
function ReplaceFuncsInSource: boolean;
function RememberProcDefinition(aNode: TCodeTreeNode): TCodeTreeNode;
function ReplaceFuncCalls: boolean;
function ReplaceFuncCalls(aIsConsoleApp: boolean): boolean;
function HandleCodetoolError: TModalResult;
public
constructor Create(Code: TCodeBuffer);
destructor Destroy; override;
function Convert: TModalResult;
function Convert(aIsConsoleApp: boolean): TModalResult;
function FindApptypeConsole: boolean;
function RemoveUnits: boolean;
function RenameUnits: boolean;
@ -126,7 +126,7 @@ begin
end;
end;
function TConvDelphiCodeTool.Convert: TModalResult;
function TConvDelphiCodeTool.Convert(aIsConsoleApp: boolean): TModalResult;
// add {$mode delphi} directive
// remove {$R *.dfm} or {$R *.xfm} directive
// Change {$R *.RES} to {$R *.res} if needed
@ -139,7 +139,7 @@ begin
// these changes can be applied together without rescan
if not AddModeDelphiDirective then exit;
if not RenameResourceDirectives then exit;
if not ReplaceFuncCalls then exit;
if not ReplaceFuncCalls(aIsConsoleApp) then exit;
if not fSrcCache.Apply then exit;
finally
fSrcCache.EndUpdate;
@ -508,7 +508,7 @@ var
ParamList: TStringList;
BodyEnd: Integer; // End of function body.
function ParseReplacementParams(aStr: string): integer;
function ParseReplacementParams(const aStr: string): integer;
// Parse replacement params. They show which original params are copied where.
// Returns the first position where comments can be searched from.
var
@ -549,7 +549,7 @@ var
end;
end;
function GetComment(aStr: string; aPossibleStartPos: integer): string;
function GetComment(const aStr: string; aPossibleStartPos: integer): string;
// Extract and return a possible comment.
var
CommChBeg, CommBeg, CommEnd, i: Integer; // Start and end of comment.
@ -630,10 +630,10 @@ begin
Result:=aNode.Next;
end;
function TConvDelphiCodeTool.ReplaceFuncCalls: boolean;
function TConvDelphiCodeTool.ReplaceFuncCalls(aIsConsoleApp: boolean): boolean;
// Copied and modified from TFindDeclarationTool.FindReferences.
// Search for calls to functions / procedures given in a list in current unit's
// implementation section. Add their positions to another list for replacement.
// Search for calls to functions / procedures in a list from current unit's
// implementation section. Replace found calls with a given replacement.
var
xStart: Integer;
@ -695,7 +695,7 @@ var
procedure ReadFuncCall(MaxPos: Integer);
var
FuncInfo: TFuncReplacement;
FuncDefInfo, FuncCallInfo: TFuncReplacement;
FuncName: string;
i, x, IdentEndPos: Integer;
begin
@ -709,12 +709,17 @@ var
and (CompareIdentifiers(PChar(Pointer(FuncName)),@Src[xStart])=0)
and not fDefinedProcNames.Find(FuncName, x)
then begin
// Create a new replacement object for params, position and other info.
FuncInfo:=TFuncReplacement.Create(fReplaceFuncs.FuncAtInd(i));
ReadParams(FuncInfo);
IdentEndPos:=FuncInfo.EndPos; // Skip the params, too, for next search.
fFuncsToReplace.Add(FuncInfo);
Break;
FuncDefInfo:=fReplaceFuncs.FuncAtInd(i);
if fReplaceFuncs.CategoryInUse.Find(FuncDefInfo.Category, x)
and not (aIsConsoleApp and (FuncDefInfo.Category='UTF8Names'))
then begin
// Create a new replacement object for params, position and other info.
FuncCallInfo:=TFuncReplacement.Create(FuncDefInfo);
ReadParams(FuncCallInfo);
IdentEndPos:=FuncCallInfo.EndPos; // Skip the params, too, for next search.
fFuncsToReplace.Add(FuncCallInfo);
Break;
end;
end;
end;
end;

View File

@ -492,6 +492,7 @@ function TConvertDelphiUnit.ConvertUnitFile: TModalResult;
var
DfmFilename: string; // Delphi .DFM file name.
LfmFilename: string; // Lazarus .LFM file name.
ConsApp: Boolean;
ConvTool: TConvDelphiCodeTool;
begin
fUnitsToRemove:=TStringList.Create;
@ -546,7 +547,11 @@ begin
// Fix or comment missing units, show error messages.
Result:=FixMissingUnits;
if Result<>mrOk then exit;
// Check from the project if this is a console application.
if Assigned(fOwnerConverter) then
ConsApp:=fOwnerConverter.fIsConsoleApp
else
ConsApp:=False;
// Do the actual code conversion.
ConvTool.Ask:=Assigned(fOwnerConverter);
ConvTool.LowerCaseRes:=FileExistsUTF8(ChangeFileExt(fLazUnitFilename, '.res'));
@ -556,7 +561,7 @@ begin
ConvTool.UnitsToRemove:=fUnitsToRemove;
ConvTool.UnitsToRename:=fUnitsToRename;
ConvTool.UnitsToComment:=fUnitsToComment;
Result:=ConvTool.Convert;
Result:=ConvTool.Convert(ConsApp);
finally
ConvTool.Free;
fUnitsToComment.Free;

View File

@ -237,15 +237,15 @@ begin
Config.DeletePath(SubPath);
end;
// Categories
Config.SetDeleteValue(CategPath+'Count', aFuncsAndCateg.CategInUse.Count, 0);
for i:=0 to aFuncsAndCateg.CategInUse.Count-1 do begin
s:=aFuncsAndCateg.CategInUse[i];
Config.SetDeleteValue(CategPath+'Count', aFuncsAndCateg.CategoryInUse.Count, 0);
for i:=0 to aFuncsAndCateg.CategoryInUse.Count-1 do begin
s:=aFuncsAndCateg.CategoryInUse[i];
if s<>'' then begin
SubPath:=CategPath+'Item'+IntToStr(i)+'/';
Config.SetDeleteValue(SubPath+'Name',s,'');
end;
end;
for i:=aFuncsAndCateg.CategInUse.Count to aFuncsAndCateg.CategInUse.Count+10 do begin
for i:=aFuncsAndCateg.CategoryInUse.Count to aFuncsAndCateg.CategoryInUse.Count+10 do begin
SubPath:=CategPath+'Item'+IntToStr(i)+'/';
Config.DeletePath(SubPath);
end;
@ -257,6 +257,7 @@ end;
constructor TConvertSettings.Create(const ATitle: string);
var
TheMap: TStringToStringTree;
Categ: string;
procedure MapReplacement(ADelphi, ALCL: string);
begin
@ -324,18 +325,44 @@ begin
MapReplacement('^TTnt(.+[^L][^X])$','T$1');
// Map Delphi function names to FCL/LCL functions.
fReplaceFuncs.AddFunc('Other', 'ShellExecute',
'if $3 match ":/" then OpenURL($3); OpenDocument($3)', '', '');
// File name encoding. ToDo: add other similar funcs with UTF8 counterparts.
fReplaceFuncs.AddFunc('UTF8Names', 'FileExists', 'FileExistsUTF8($1)', '', '');
// File functions using a handle.
fReplaceFuncs.AddFunc('Other', 'CreateFile', 'FileCreate($1)', '', 'SysUtils');
fReplaceFuncs.AddFunc('Other', 'GetFileSize', 'FileSize($1)' , '', 'SysUtils');
fReplaceFuncs.AddFunc('Other', 'ReadFile', 'FileRead($1)' , '', 'SysUtils');
fReplaceFuncs.AddFunc('Other', 'CloseHandle', 'FileClose($1)' , '', 'SysUtils');
// Categories.
fReplaceFuncs.AddCategory('UTF8Names');
fReplaceFuncs.AddCategory('Other');
with fReplaceFuncs do begin
// File name encoding.
Categ:='UTF8Names';
if AddFunc(Categ,'FileExists', 'FileExistsUTF8($1)','LCL','FileUtil')<>-1 then
AddCategory(Categ); // Use the category by default if the func was added.
AddFunc(Categ,'FileAge', 'FileAgeUTF8($1)', 'LCL','FileUtil');
AddFunc(Categ,'DirectoryExists', 'DirectoryExistsUTF8($1)', 'LCL','FileUtil');
AddFunc(Categ,'ExpandFileName', 'ExpandFileNameUTF8($1)', 'LCL','FileUtil');
AddFunc(Categ,'ExpandUNCFileName', 'ExpandUNCFileNameUTF8($1)', 'LCL','FileUtil');
AddFunc(Categ,'ExtractShortPathName','ExtractShortPathNameUTF8($1)','LCL','FileUtil');
AddFunc(Categ,'FindFirst', 'FindFirstUTF8($1,$2,$3)', 'LCL','FileUtil');
AddFunc(Categ,'FindNext', 'FindNextUTF8($1)', 'LCL','FileUtil');
AddFunc(Categ,'FindClose', 'FindCloseUTF8($1)', 'LCL','FileUtil');
AddFunc(Categ,'FileSetDate', 'FileSetDateUTF8($1,$2)', 'LCL','FileUtil');
AddFunc(Categ,'FileGetAttr', 'FileGetAttrUTF8($1)', 'LCL','FileUtil');
AddFunc(Categ,'FileSetAttr', 'FileSetAttrUTF8($1)', 'LCL','FileUtil');
AddFunc(Categ,'DeleteFile', 'DeleteFileUTF8($1)', 'LCL','FileUtil');
AddFunc(Categ,'RenameFile', 'RenameFileUTF8($1,$2)', 'LCL','FileUtil');
AddFunc(Categ,'FileSearch', 'FileSearchUTF8($1,$2)', 'LCL','FileUtil');
AddFunc(Categ,'FileIsReadOnly', 'FileIsReadOnlyUTF8($1)', 'LCL','FileUtil');
AddFunc(Categ,'GetCurrentDir', 'GetCurrentDirUTF8', 'LCL','FileUtil');
AddFunc(Categ,'SetCurrentDir', 'SetCurrentDirUTF8($1)', 'LCL','FileUtil');
AddFunc(Categ,'CreateDir', 'CreateDirUTF8($1)', 'LCL','FileUtil');
AddFunc(Categ,'RemoveDir', 'RemoveDirUTF8($1)', 'LCL','FileUtil');
AddFunc(Categ,'ForceDirectories', 'ForceDirectoriesUTF8($1)', 'LCL','FileUtil');
// File functions using a handle.
Categ:='FileHandle';
if AddFunc(Categ,'CreateFile','FileCreate($1)','','SysUtils')<>-1 then
AddCategory(Categ);
AddFunc(Categ, 'GetFileSize','FileSize($1)' ,'','SysUtils');
AddFunc(Categ, 'ReadFile', 'FileRead($1)' ,'','SysUtils');
AddFunc(Categ, 'CloseHandle','FileClose($1)','','SysUtils');
// Others
Categ:='Other';
if AddFunc(Categ, 'ShellExecute',
'if $3 match ":/" then OpenURL($3); OpenDocument($3)', '', '')<>-1 then
AddCategory(Categ);
end;
end;
destructor TConvertSettings.Destroy;

View File

@ -1,18 +1,19 @@
object ReplaceFuncsForm: TReplaceFuncsForm
Left = 361
Height = 321
Top = 90
Width = 856
Left = 508
Height = 626
Top = 104
Width = 928
Caption = 'Functions to replace'
ClientHeight = 321
ClientWidth = 856
ClientHeight = 626
ClientWidth = 928
OnCreate = FormCreate
Position = poScreenCenter
LCLVersion = '0.9.29'
object ButtonPanel: TButtonPanel
Left = 6
Height = 39
Top = 276
Width = 844
Top = 581
Width = 916
OKButton.Name = 'OKButton'
OKButton.Caption = '&OK'
OKButton.OnClick = OKButtonClick
@ -27,19 +28,22 @@ object ReplaceFuncsForm: TReplaceFuncsForm
ShowButtons = [pbOK, pbCancel, pbHelp]
end
object Grid: TStringGrid
AnchorSideLeft.Control = Splitter1
AnchorSideLeft.Side = asrBottom
AnchorSideBottom.Control = ButtonPanel
Left = 162
Height = 270
Height = 575
Top = 0
Width = 694
Align = alClient
Width = 766
Anchors = [akTop, akLeft, akRight, akBottom]
Columns = <
item
Title.Caption = 'Category'
Width = 80
Width = 100
end
item
Title.Caption = 'Delphi Function'
Width = 120
Width = 150
end
item
Title.Caption = 'Replacement'
@ -47,11 +51,11 @@ object ReplaceFuncsForm: TReplaceFuncsForm
end
item
Title.Caption = 'Package'
Width = 100
Width = 90
end
item
Title.Caption = 'Unit'
Width = 100
Width = 90
end>
FixedCols = 0
Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goDrawFocusSelected, goEditing, goSmoothScroll]
@ -59,19 +63,24 @@ object ReplaceFuncsForm: TReplaceFuncsForm
RowCount = 2
TabOrder = 1
ColWidths = (
80
120
100
150
310
100
100
90
90
)
end
object CategoryListBox: TCheckListBox
AnchorSideTop.Control = CategoriesLabel
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = Splitter1
AnchorSideBottom.Control = ButtonPanel
Left = 0
Height = 270
Top = 0
Height = 546
Top = 29
Width = 157
Align = alLeft
Anchors = [akTop, akLeft, akRight, akBottom]
BorderSpacing.Top = 5
ItemHeight = 0
TabOrder = 2
end
@ -80,6 +89,17 @@ object ReplaceFuncsForm: TReplaceFuncsForm
Height = 270
Top = 0
Width = 5
Align = alNone
end
object CategoriesLabel: TLabel
Left = 6
Height = 16
Top = 8
Width = 131
Caption = 'Categories to convert :'
Font.Height = -13
ParentColor = False
ParentFont = False
end
object PopupMenu1: TPopupMenu
OnPopup = PopupMenu1Popup

View File

@ -6,7 +6,7 @@ interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
Buttons, ButtonPanel, ComCtrls, Grids, CheckLst, Menus, SynRegExpr,
Buttons, ButtonPanel, ComCtrls, Grids, CheckLst, Menus, StdCtrls, SynRegExpr,
LazarusIDEStrConsts, ConverterTypes;
type
@ -61,7 +61,7 @@ type
function FuncAtInd(Ind: integer): TFuncReplacement;
public
property Funcs: TStringList read fFuncs;
property CategInUse: TStringList read fCategInUse;
property CategoryInUse: TStringList read fCategInUse;
end;
{ TReplaceFuncsForm }
@ -72,6 +72,7 @@ type
DeleteRow1: TMenuItem;
Grid: TStringGrid;
InsertRow1: TMenuItem;
CategoriesLabel: TLabel;
PopupMenu1: TPopupMenu;
Splitter1: TSplitter;
procedure FormCreate(Sender: TObject);
@ -280,6 +281,8 @@ begin
fFuncs.Sorted:=True;
fFuncs.CaseSensitive:=False;
fCategInUse:=TStringList.Create;
fCategInUse.Sorted:=True;
fCategInUse.Duplicates:=dupIgnore;
end;
destructor TFuncsAndCategories.Destroy;
@ -302,6 +305,7 @@ end;
function TFuncsAndCategories.AddFunc(
aCategory, aDelphiFunc, aReplaceFunc, aPackage, aUnitName: string): integer;
// This is called when settings are read or when user made changes in GUI.
// Returns index for the added func replacement, or -1 if not added (duplicate).
var
FuncRepl: TFuncReplacement;
x: integer;
@ -395,10 +399,10 @@ begin
NewCategories:=TStringList.Create;
NewCategories.Sorted:=True;
try
Grid.BeginUpdate;
for i:=1 to aFuncsAndCateg.fFuncs.Count do begin // Skip the fixed row in grid.
Grid.BeginUpdate; // Skip the fixed row in grid.
for i:=1 to aFuncsAndCateg.fFuncs.Count do begin
if Grid.RowCount<i+2 then
Grid.RowCount:=i+2; // Leave one empty row to the end.
Grid.RowCount:=i+2; // Leave one empty row to the end.
FuncRepl:=TFuncReplacement(aFuncsAndCateg.fFuncs.Objects[i-1]);
Grid.Cells[0,i]:=FuncRepl.fCategory;
Grid.Cells[1,i]:=aFuncsAndCateg.fFuncs[i-1]; // Delphi function name
@ -409,7 +413,7 @@ begin
CategoryListBox.Items.Add(FuncRepl.fCategory);
NewCatInd:=NewCategories.Add(FuncRepl.fCategory);
CategoryListBox.Checked[NewCatInd]:=
aFuncsAndCateg.fCategInUse.Find(FuncRepl.fCategory, x);
aFuncsAndCateg.fCategInUse.Find(FuncRepl.fCategory, x);
end;
end;
Grid.EndUpdate;