mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-25 19:02:44 +02:00
IDE+codetools: started heuristic to find unused units
git-svn-id: trunk@19281 -
This commit is contained in:
parent
b96aabcd76
commit
26ef5cd496
3
.gitattributes
vendored
3
.gitattributes
vendored
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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';
|
||||||
|
12
ide/main.pp
12
ide/main.pp
@ -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;
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
|
@ -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,6 +1017,11 @@ 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');
|
||||||
@ -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
28
ide/unusedunitsdlg.lfm
Normal 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
12
ide/unusedunitsdlg.lrs
Normal 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
112
ide/unusedunitsdlg.pas
Normal 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.
|
||||||
|
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user