IDE+codetools: started heuristic to find unused units

git-svn-id: trunk@19281 -
This commit is contained in:
mattias 2009-04-08 23:45:15 +00:00
parent b96aabcd76
commit 26ef5cd496
14 changed files with 399 additions and 4 deletions

3
.gitattributes vendored
View File

@ -2824,6 +2824,9 @@ ide/unitdependencies.pas svneol=native#text/pascal
ide/unitinfodlg.lfm svneol=native#text/plain ide/unitinfodlg.lfm svneol=native#text/plain
ide/unitinfodlg.lrs svneol=native#text/plain ide/unitinfodlg.lrs svneol=native#text/plain
ide/unitinfodlg.pp svneol=native#text/pascal ide/unitinfodlg.pp svneol=native#text/pascal
ide/unusedunitsdlg.lfm svneol=native#text/plain
ide/unusedunitsdlg.lrs svneol=native#text/plain
ide/unusedunitsdlg.pas svneol=native#text/plain
ide/version.inc svneol=native#text/plain ide/version.inc svneol=native#text/plain
ide/versioninfoadditionalinfo.lfm svneol=native#text/plain ide/versioninfoadditionalinfo.lfm svneol=native#text/plain
ide/versioninfoadditionalinfo.lrs svneol=native#text/plain ide/versioninfoadditionalinfo.lrs svneol=native#text/plain

View File

@ -488,6 +488,7 @@ type
out AllRemoved: boolean; out AllRemoved: boolean;
const Attr: TProcHeadAttributes; const Attr: TProcHeadAttributes;
out RemovedProcHeads: TStrings): boolean; out RemovedProcHeads: TStrings): boolean;
function FindUnusedUnits(Code: TCodeBuffer; Units: TStrings): boolean;
// custom class completion // custom class completion
function InitClassCompletion(Code: TCodeBuffer; function InitClassCompletion(Code: TCodeBuffer;
@ -3480,6 +3481,21 @@ begin
end; end;
end; end;
function TCodeToolManager.FindUnusedUnits(Code: TCodeBuffer; Units: TStrings
): boolean;
begin
{$IFDEF CTDEBUG}
DebugLn('TCodeToolManager.FindEmptyMethods A ',Code.Filename);
{$ENDIF}
Result:=false;
if not InitCurCodeTool(Code) then exit;
try
Result:=FCurCodeTool.FindUnusedUnits(Units);
except
on e: Exception do Result:=HandleException(e);
end;
end;
function TCodeToolManager.InitClassCompletion(Code: TCodeBuffer; function TCodeToolManager.InitClassCompletion(Code: TCodeBuffer;
const UpperClassName: string; out CodeTool: TCodeTool): boolean; const UpperClassName: string; out CodeTool: TCodeTool): boolean;
begin begin

View File

@ -1752,7 +1752,7 @@ begin
UnitNamePos.EndPos-UnitNamePos.StartPos); UnitNamePos.EndPos-UnitNamePos.StartPos);
if UnitInFilePos.StartPos>=1 then begin if UnitInFilePos.StartPos>=1 then begin
UnitInFilename:=copy(Src,UnitInFilePos.StartPos+1, UnitInFilename:=copy(Src,UnitInFilePos.StartPos+1,
UnitInFilePos.EndPos-UnitInFilePos.StartPos-2) UnitInFilePos.EndPos-UnitInFilePos.StartPos-2);
end else end else
UnitInFilename:=''; UnitInFilename:='';
NewPos.Code:=FindUnitSource(UnitName,UnitInFilename,true); NewPos.Code:=FindUnitSource(UnitName,UnitInFilename,true);

View File

@ -1787,7 +1787,7 @@ begin
then then
RaiseException('[TPascalParserTool.MoveCursorToUsesStart] ' RaiseException('[TPascalParserTool.MoveCursorToUsesStart] '
+'internal error: invalid UsesNode'); +'internal error: invalid UsesNode');
// search backwards through the uses section // search through the uses section
MoveCursorToCleanPos(UsesNode.StartPos); MoveCursorToCleanPos(UsesNode.StartPos);
ReadNextAtom; ReadNextAtom;
if (not UpAtomIs('USES')) and (not UpAtomIs('CONTAINS')) then if (not UpAtomIs('USES')) and (not UpAtomIs('CONTAINS')) then

View File

@ -118,6 +118,7 @@ type
SourceChangeCache: TSourceChangeCache): boolean; SourceChangeCache: TSourceChangeCache): boolean;
function CommentUnitsInUsesSections(MissingUnits: TStrings; function CommentUnitsInUsesSections(MissingUnits: TStrings;
SourceChangeCache: TSourceChangeCache): boolean; SourceChangeCache: TSourceChangeCache): boolean;
function FindUnusedUnits(Units: TStrings): boolean;
// lazarus resources // lazarus resources
function FindNextIncludeInInitialization( function FindNextIncludeInInitialization(
@ -1327,6 +1328,198 @@ begin
Result:=true; Result:=true;
end; end;
function TStandardCodeTool.FindUnusedUnits(Units: TStrings): boolean;
// returns a list of unitname=flags
// flags are a comma separated list of words:
// 'implementation': unit is in implementation uses section
// 'used': an identifier of the interface is used
// 'code': unit has non empty initialization/finalization section
var
Identifiers: TAVLTree;// all identifiers used in this unit
procedure RaiseUsesExpected;
begin
RaiseExceptionFmt(ctsStrExpectedButAtomFound,['"uses"',GetAtom]);
end;
procedure RaiseStrConstExpected;
begin
RaiseExceptionFmt(ctsStrExpectedButAtomFound,[ctsStringConstant,GetAtom]);
end;
function IsUnitAlreadyChecked(const AnUnitName: string): boolean;
var
i: Integer;
begin
for i:=0 to Units.Count-1 do
if SysUtils.CompareText(Units.Names[i],AnUnitName)=0 then exit(true);
Result:=false;
end;
procedure GatherIdentifiers;
var
Node: TCodeTreeNode;
Identifier: PChar;
begin
if Identifiers<>nil then exit;
Identifiers:=TAVLTree.Create(@CompareIdentifierPtrs);
Node:=Tree.Root;
while Node<>nil do begin
if (Node.Desc in [ctnBeginBlock,ctnAsmBlock])
or ((Node.FirstChild=nil)
and (Node.Desc in [ctnIdentifier,ctnRangedArrayType,ctnOpenArrayType,
ctnOfConstType,ctnRecordVariant,ctnProcedureType,ctnRangeType,
ctnTypeType,ctnFileType,ctnPointerType,ctnClassOfType,
ctnSpecializeParams,ctnGenericParameter,ctnConstant]))
then begin
MoveCursorToNodeStart(Node);
repeat
ReadNextAtom;
if CurPos.StartPos>=Node.EndPos then break;
if IsIdentStartChar[Src[CurPos.StartPos]] then begin
Identifier:=@Src[CurPos.StartPos];
if Identifiers.Find(Identifier)=nil then begin
DebugLn(['GatherIdentifiers ',GetIdentifier(Identifier)]);
Identifiers.Add(Identifier);
end;
end;
until false;
Node:=Node.NextSkipChilds;
end else
Node:=Node.Next;
end;
end;
function InterfaceIsUsed(Tool: TFindDeclarationTool;
IntfNode: TCodeTreeNode): boolean;
function IsIdentifierUsed(StartPos: integer): boolean;
begin
Result:=Identifiers.Find(@Tool.Src[StartPos])<>nil;
end;
var
Node: TCodeTreeNode;
begin
Result:=true;
Node:=IntfNode.FirstChild;
while Node<>nil do begin
case Node.Desc of
ctnEnumIdentifier:
if IsIdentifierUsed(Node.StartPos) then exit;
end;
Node:=Node.Next;
end;
Result:=false;
end;
procedure CheckUnit(Tool: TFindDeclarationTool;
out HasCode, UseInterface: boolean);
var
Node: TCodeTreeNode;
Identifier: String;
begin
GatherIdentifiers;
HasCode:=false;
UseInterface:=false;
// parse used unit
Tool.BuildTree(false);
Node:=Tool.Tree.Root;
while (Node<>nil) do begin
case Node.Desc of
ctnUnit,ctnPackage,ctnLibrary:
begin
Identifier:=Tool.ExtractSourceName;
if Identifiers.Find(PChar(Identifier))<>nil then
UseInterface:=true;
end;
ctnInterface:
if not UseInterface then
UseInterface:=InterfaceIsUsed(Tool,Node);
ctnInitialization,ctnFinalization,ctnBeginBlock:
begin
HasCode:=true;
break;
end;
end;
Node:=Node.NextBrother;
end;
end;
procedure CheckUsesSection(UsesNode: TCodeTreeNode; InImplementation: boolean);
var
UnitNamePos: TAtomPosition;
UnitInFilePos: TAtomPosition;
UnitName: String;
UnitInFilename: String;
Tool: TFindDeclarationTool;
HasCode: boolean;
UseInterface: boolean;
Flags: String;
begin
HasCode:=false;
UseInterface:=false;
if UsesNode=nil then exit;
MoveCursorToNodeStart(UsesNode);
ReadNextAtom;
if not UpAtomIs('USES') then
RaiseUsesExpected;
repeat
ReadNextAtom; // read name
if AtomIsChar(';') then break;
AtomIsIdentifier(true);
UnitNamePos:=CurPos;
ReadNextAtom;
if UpAtomIs('IN') then begin
ReadNextAtom;
if not AtomIsStringConstant then RaiseStrConstExpected;
UnitInFilePos:=CurPos;
ReadNextAtom;
end else
UnitInFilePos.StartPos:=-1;
UnitName:=copy(Src,UnitNamePos.StartPos,
UnitNamePos.EndPos-UnitNamePos.StartPos);
if not IsUnitAlreadyChecked(UnitName) then begin
if UnitInFilePos.StartPos>=1 then begin
UnitInFilename:=copy(Src,UnitInFilePos.StartPos+1,
UnitInFilePos.EndPos-UnitInFilePos.StartPos-2);
end else
UnitInFilename:='';
// try to load the used unit
DebugLn(['CheckUsesSection ',UnitName,UnitInFilename]);
Tool:=FindCodeToolForUsedUnit(UnitName,UnitInFilename,true);
// parse the used unit
CheckUnit(Tool,HasCode,UseInterface);
Flags:='';
if InImplementation then
Flags:=Flags+',implementation';
if HasCode then
Flags:=Flags+',code';
if UseInterface then
Flags:=Flags+',used';
DebugLn(['CheckUsesSection ',UnitName,'=',Flags]);
Units.Add(UnitName+'='+Flags);
end;
if AtomIsChar(';') then break;
if not AtomIsChar(',') then
RaiseExceptionFmt(ctsStrExpectedButAtomFound,[';',GetAtom])
until (CurPos.StartPos>SrcLen);
end;
begin
Result:=false;
DebugLn(['TStandardCodeTool.FindUnusedUnits ']);
BuildTree(false);
Identifiers:=nil;
try
CheckUsesSection(FindMainUsesSection,false);
CheckUsesSection(FindImplementationUsesSection,true);
finally
Identifiers.Free;
end;
Result:=true;
end;
function TStandardCodeTool.FindNextIncludeInInitialization( function TStandardCodeTool.FindNextIncludeInInitialization(
var LinkIndex: integer): TCodeBuffer; var LinkIndex: integer): TCodeBuffer;
// LinkIndex < 0 -> search first // LinkIndex < 0 -> search first

View File

@ -94,6 +94,7 @@ var
ListOfPCodeXYPosition: TFPList; ListOfPCodeXYPosition: TFPList;
AllEmpty: boolean; AllEmpty: boolean;
begin begin
Result:=mrCancel;
ListOfPCodeXYPosition:=TFPList.Create; ListOfPCodeXYPosition:=TFPList.Create;
try try
// init codetools // init codetools

View File

@ -403,6 +403,7 @@ begin
ecGotoIncludeDirective: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]); ecGotoIncludeDirective: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecShowAbstractMethods: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]); ecShowAbstractMethods: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecRemoveEmptyMethods: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]); ecRemoveEmptyMethods: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecRemoveUnusedUnits: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
// source notebook // source notebook
ecNextEditor: SetResult(VK_TAB, [ssCtrl], VK_UNKNOWN, []); ecNextEditor: SetResult(VK_TAB, [ssCtrl], VK_UNKNOWN, []);
@ -1760,6 +1761,7 @@ begin
ecFindBlockStart : Result:= srkmecFindBlockStart; ecFindBlockStart : Result:= srkmecFindBlockStart;
ecShowAbstractMethods : Result:= srkmecShowAbstractMethods; ecShowAbstractMethods : Result:= srkmecShowAbstractMethods;
ecRemoveEmptyMethods : Result:= srkmecRemoveEmptyMethods; ecRemoveEmptyMethods : Result:= srkmecRemoveEmptyMethods;
ecRemoveUnusedUnits : Result:= srkmecRemoveEmptyMethods;
// project (menu string resource) // project (menu string resource)
ecNewProject : Result:= lisMenuNewProject; ecNewProject : Result:= lisMenuNewProject;
@ -2220,6 +2222,8 @@ begin
ecShowAbstractMethods); ecShowAbstractMethods);
AddDefault(C, 'Remove empty methods', srkmecRemoveEmptyMethods, AddDefault(C, 'Remove empty methods', srkmecRemoveEmptyMethods,
ecRemoveEmptyMethods); ecRemoveEmptyMethods);
AddDefault(C, 'Remove unused units', srkmecRemoveUnusedUnits,
ecRemoveUnusedUnits);
// source notebook - without menu items in the IDE bar // source notebook - without menu items in the IDE bar
C:=Categories[AddCategory('SourceNotebook',srkmCatSrcNoteBook, C:=Categories[AddCategory('SourceNotebook',srkmCatSrcNoteBook,

View File

@ -1785,6 +1785,7 @@ resourcestring
lisUEDoNotSho = 'Do not show this message again.'; lisUEDoNotSho = 'Do not show this message again.';
uemInsertTodo = 'Insert Todo'; uemInsertTodo = 'Insert Todo';
lisCodeHelpShowEmptyMethods = 'Show empty methods'; lisCodeHelpShowEmptyMethods = 'Show empty methods';
lisCodeHelpShowUnusedUnits = 'Show unused units';
uemHighlighter = 'Highlighter'; uemHighlighter = 'Highlighter';
uemEncoding = 'Encoding'; uemEncoding = 'Encoding';
@ -2076,6 +2077,7 @@ resourcestring
srkmecFindBlockStart = 'Find block start'; srkmecFindBlockStart = 'Find block start';
srkmecShowAbstractMethods = 'Show abstract methods'; srkmecShowAbstractMethods = 'Show abstract methods';
srkmecRemoveEmptyMethods = 'Remove empty methods'; srkmecRemoveEmptyMethods = 'Remove empty methods';
srkmecRemoveUnusedUnits = 'Remove unused units';
// run menu // run menu
srkmecBuild = 'build program/project'; srkmecBuild = 'build program/project';

View File

@ -133,8 +133,9 @@ uses
ProcessList, InitialSetupDlgs, NewDialog, MakeResStrDlg, ToDoList, ProcessList, InitialSetupDlgs, NewDialog, MakeResStrDlg, ToDoList,
DialogProcs, FindReplaceDialog, FindInFilesDlg, CodeExplorer, BuildFileDlg, DialogProcs, FindReplaceDialog, FindInFilesDlg, CodeExplorer, BuildFileDlg,
ProcedureList, ExtractProcDlg, FindRenameIdentifier, AbstractsMethodsDlg, ProcedureList, ExtractProcDlg, FindRenameIdentifier, AbstractsMethodsDlg,
EmptyMethodsDlg, CleanDirDlg, CodeContextForm, AboutFrm, BuildManager, EmptyMethodsDlg, UnusedUnitsDlg, CleanDirDlg, CodeContextForm, AboutFrm,
CompatibilityRestrictions, RestrictionBrowser, ProjectWizardDlg, IDECmdLine, CompatibilityRestrictions, RestrictionBrowser, ProjectWizardDlg, IDECmdLine,
BuildManager,
// main ide // main ide
MainBar, MainIntf, MainBase; MainBar, MainIntf, MainBase;
@ -864,6 +865,7 @@ type
NewFilename, NewUnitName: string): TModalResult; NewFilename, NewUnitName: string): TModalResult;
function DoShowAbstractMethods: TModalResult; function DoShowAbstractMethods: TModalResult;
function DoRemoveEmptyMethods: TModalResult; function DoRemoveEmptyMethods: TModalResult;
function DoRemoveUnusedUnits: TModalResult;
function DoInitIdentCompletion(JumpToError: boolean): boolean; function DoInitIdentCompletion(JumpToError: boolean): boolean;
function DoShowCodeContext(JumpToError: boolean): boolean; function DoShowCodeContext(JumpToError: boolean): boolean;
procedure DoCompleteCodeAtCursor; procedure DoCompleteCodeAtCursor;
@ -2771,6 +2773,9 @@ begin
ecRemoveEmptyMethods: ecRemoveEmptyMethods:
DoRemoveEmptyMethods; DoRemoveEmptyMethods;
ecRemoveUnusedUnits:
DoRemoveUnusedUnits;
ecFindBlockOtherEnd: ecFindBlockOtherEnd:
DoGoToPascalBlockOtherEnd; DoGoToPascalBlockOtherEnd;
@ -12713,6 +12718,11 @@ begin
Result:=ShowEmptyMethodsDialog; Result:=ShowEmptyMethodsDialog;
end; end;
function TMainIDE.DoRemoveUnusedUnits: TModalResult;
begin
Result:=ShowUnusedUnitsDialog;
end;
{------------------------------------------------------------------------------- {-------------------------------------------------------------------------------
function TMainIDE.DoInitIdentCompletion(JumpToError: boolean): boolean; function TMainIDE.DoInitIdentCompletion(JumpToError: boolean): boolean;
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}

View File

@ -433,6 +433,7 @@ type
procedure RenameIdentifierMenuItemClick(Sender: TObject); procedure RenameIdentifierMenuItemClick(Sender: TObject);
procedure ShowAbstractMethodsMenuItemClick(Sender: TObject); procedure ShowAbstractMethodsMenuItemClick(Sender: TObject);
procedure ShowEmptyMethodsMenuItemClick(Sender: TObject); procedure ShowEmptyMethodsMenuItemClick(Sender: TObject);
procedure ShowUnusedUnitsMenuItemClick(Sender: TObject);
procedure RunToClicked(Sender: TObject); procedure RunToClicked(Sender: TObject);
procedure ViewCallStackClick(Sender: TObject); procedure ViewCallStackClick(Sender: TObject);
procedure AddWatchAtCursor(Sender: TObject); procedure AddWatchAtCursor(Sender: TObject);
@ -857,6 +858,7 @@ var
SrcEditMenuInvertAssignment: TIDEMenuCommand; SrcEditMenuInvertAssignment: TIDEMenuCommand;
SrcEditMenuShowAbstractMethods: TIDEMenuCommand; SrcEditMenuShowAbstractMethods: TIDEMenuCommand;
SrcEditMenuShowEmptyMethods: TIDEMenuCommand; SrcEditMenuShowEmptyMethods: TIDEMenuCommand;
SrcEditMenuShowUnusedUnits: TIDEMenuCommand;
SrcEditMenuInsertTodo: TIDEMenuCommand; SrcEditMenuInsertTodo: TIDEMenuCommand;
SrcEditMenuMoveEditorLeft: TIDEMenuCommand; SrcEditMenuMoveEditorLeft: TIDEMenuCommand;
SrcEditMenuMoveEditorRight: TIDEMenuCommand; SrcEditMenuMoveEditorRight: TIDEMenuCommand;
@ -1015,9 +1017,14 @@ begin
'ShowAbstractMethods',srkmecShowAbstractMethods); 'ShowAbstractMethods',srkmecShowAbstractMethods);
SrcEditMenuShowEmptyMethods:=RegisterIDEMenuCommand(AParent, SrcEditMenuShowEmptyMethods:=RegisterIDEMenuCommand(AParent,
'ShowEmptyMethods', lisCodeHelpShowEmptyMethods); 'ShowEmptyMethods', lisCodeHelpShowEmptyMethods);
SrcEditMenuShowUnusedUnits:=RegisterIDEMenuCommand(AParent,
'ShowUnusedUnits', lisCodeHelpShowUnusedUnits);
{$IFNDEF EnableUnusedUnits}
SrcEditMenuShowUnusedUnits.Visible:=false;
{$ENDIF}
SrcEditMenuInsertTodo:=RegisterIDEMenuCommand(SourceEditorMenuRoot, SrcEditMenuInsertTodo:=RegisterIDEMenuCommand(SourceEditorMenuRoot,
'InsertTodo',uemInsertTodo, nil, nil, nil, 'item_todo'); 'InsertTodo',uemInsertTodo, nil, nil, nil, 'item_todo');
// register the Flags section // register the Flags section
SrcEditSubMenuFlags:=RegisterIDESubMenu(SourceEditorMenuRoot, SrcEditSubMenuFlags:=RegisterIDESubMenu(SourceEditorMenuRoot,
@ -4383,6 +4390,7 @@ begin
SrcEditMenuRenameIdentifier.OnClick:=@RenameIdentifierMenuItemClick; SrcEditMenuRenameIdentifier.OnClick:=@RenameIdentifierMenuItemClick;
SrcEditMenuShowAbstractMethods.OnClick:=@ShowAbstractMethodsMenuItemClick; SrcEditMenuShowAbstractMethods.OnClick:=@ShowAbstractMethodsMenuItemClick;
SrcEditMenuShowEmptyMethods.OnClick:=@ShowEmptyMethodsMenuItemClick; SrcEditMenuShowEmptyMethods.OnClick:=@ShowEmptyMethodsMenuItemClick;
SrcEditMenuShowUnusedUnits.OnClick:=@ShowUnusedUnitsMenuItemClick;
SrcEditMenuReadOnly.OnClick:=@ReadOnlyClicked; SrcEditMenuReadOnly.OnClick:=@ReadOnlyClicked;
SrcEditMenuShowLineNumbers.OnClick:=@ToggleLineNumbersClicked; SrcEditMenuShowLineNumbers.OnClick:=@ToggleLineNumbersClicked;
@ -5627,6 +5635,11 @@ begin
MainIDEInterface.DoCommand(ecRemoveEmptyMethods); MainIDEInterface.DoCommand(ecRemoveEmptyMethods);
end; end;
procedure TSourceNotebook.ShowUnusedUnitsMenuItemClick(Sender: TObject);
begin
MainIDEInterface.DoCommand(ecRemoveUnusedUnits);
end;
procedure TSourceNotebook.RunToClicked(Sender: TObject); procedure TSourceNotebook.RunToClicked(Sender: TObject);
var var
ASrcEdit: TSourceEditor; ASrcEdit: TSourceEditor;

28
ide/unusedunitsdlg.lfm Normal file
View File

@ -0,0 +1,28 @@
object UnusedUnitsDialog: TUnusedUnitsDialog
Left = 375
Height = 365
Top = 236
Width = 340
Caption = 'UnusedUnitsDialog'
ClientHeight = 365
ClientWidth = 340
OnCreate = FormCreate
LCLVersion = '0.9.27'
object ButtonPanel1: TButtonPanel
Left = 6
Height = 44
Top = 315
Width = 328
TabOrder = 0
ShowButtons = [pbOK, pbCancel]
end
object UnitsTreeView: TTreeView
Left = 0
Height = 309
Top = 0
Width = 340
Align = alClient
DefaultItemHeight = 19
TabOrder = 1
end
end

12
ide/unusedunitsdlg.lrs Normal file
View File

@ -0,0 +1,12 @@
{ This is an automatically generated lazarus resource file }
LazarusResources.Add('TUnusedUnitsDialog','FORMDATA',[
'TPF0'#18'TUnusedUnitsDialog'#17'UnusedUnitsDialog'#4'Left'#3'w'#1#6'Height'#3
+'m'#1#3'Top'#3#236#0#5'Width'#3'T'#1#7'Caption'#6#17'UnusedUnitsDialog'#12'C'
+'lientHeight'#3'm'#1#11'ClientWidth'#3'T'#1#8'OnCreate'#7#10'FormCreate'#10
+'LCLVersion'#6#6'0.9.27'#0#12'TButtonPanel'#12'ButtonPanel1'#4'Left'#2#6#6'H'
+'eight'#2','#3'Top'#3';'#1#5'Width'#3'H'#1#8'TabOrder'#2#0#11'ShowButtons'#11
+#4'pbOK'#8'pbCancel'#0#0#0#9'TTreeView'#13'UnitsTreeView'#4'Left'#2#0#6'Heig'
+'ht'#3'5'#1#3'Top'#2#0#5'Width'#3'T'#1#5'Align'#7#8'alClient'#17'DefaultItem'
+'Height'#2#19#8'TabOrder'#2#1#0#0#0
]);

112
ide/unusedunitsdlg.pas Normal file
View File

@ -0,0 +1,112 @@
{
***************************************************************************
* *
* This source is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This code is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License for more details. *
* *
* A copy of the GNU General Public License is available on the World *
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
* obtain it by writing to the Free Software Foundation, *
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
* *
***************************************************************************
Author: Mattias Gaertner
Abstract:
A dialog showing the unused units of the current unit
(at cursor in source editor).
With the ability to remove them automatically.
}
unit UnusedUnitsDlg;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, LCLProc,FileUtil, LResources, Forms, Controls, Graphics,
Dialogs, ButtonPanel, ComCtrls,
SrcEditorIntf, LazIDEIntf,
CodeCache, CodeToolManager,
LazarusIDEStrConsts;
type
{ TUnusedUnitsDialog }
TUnusedUnitsDialog = class(TForm)
ButtonPanel1: TButtonPanel;
UnitsTreeView: TTreeView;
procedure FormCreate(Sender: TObject);
procedure OkClick(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
var
UnusedUnitsDialog: TUnusedUnitsDialog;
function ShowUnusedUnitsDialog: TModalResult;
implementation
function ShowUnusedUnitsDialog: TModalResult;
var
SrcEdit: TSourceEditorInterface;
Code: TCodeBuffer;
Units: TStringList;
begin
Result:=mrOk;
if not LazarusIDE.BeginCodeTools then exit;
// get cursor position
SrcEdit:=SourceEditorWindow.ActiveEditor;
if SrcEdit=nil then exit;
Code:=TCodeBuffer(SrcEdit.CodeToolsBuffer);
if Code=nil then exit;
Units:=TStringList.Create;
try
if not CodeToolBoss.FindUnusedUnits(Code,Units) then begin
DebugLn(['ShowUnusedUnitsDialog CodeToolBoss.FindUnusedUnits failed']);
LazarusIDE.DoJumpToCodeToolBossError;
exit(mrCancel);
end;
finally
Units.Free;
end;
end;
{ TUnusedUnitsDialog }
procedure TUnusedUnitsDialog.FormCreate(Sender: TObject);
begin
Caption:='Unused units';
ButtonPanel1.OKButton.Caption:='Remove selected units';
ButtonPanel1.OKButton.OnClick:=@OkClick;
ButtonPanel1.CancelButton.Caption:='Cancel';
end;
procedure TUnusedUnitsDialog.OkClick(Sender: TObject);
begin
end;
initialization
{$I unusedunitsdlg.lrs}
end.

View File

@ -139,6 +139,7 @@ const
ecShowCodeContext = ecFirstLazarus + 118; ecShowCodeContext = ecFirstLazarus + 118;
ecShowAbstractMethods = ecFirstLazarus + 119; ecShowAbstractMethods = ecFirstLazarus + 119;
ecRemoveEmptyMethods = ecFirstLazarus + 120; ecRemoveEmptyMethods = ecFirstLazarus + 120;
ecRemoveUnusedUnits = ecFirstLazarus + 121;
// file menu // file menu
ecNew = ecFirstLazarus + 201; ecNew = ecFirstLazarus + 201;