codetools: FindSourceNameReferences: elimnate duplicates

This commit is contained in:
mattias 2025-02-06 10:24:39 +01:00
parent 4ce84e7af4
commit 287832a0e8
2 changed files with 204 additions and 7 deletions

View File

@ -573,7 +573,7 @@ type
function FindSourceNameReferences(TargetFilename: string;
Files: TStringList; SkipComments: boolean;
out ListOfSrcNameRefs: TObjectList): boolean;
out ListOfSrcNameRefs: TObjectList; WithDuplicates: boolean = false): boolean;
function RenameSourceNameReferences(OldFilename, NewFilename, NewSrcname: string;
ListOfSrcNameRefs: TObjectList): boolean;
// todo: deprecate FindUnitReferences
@ -3048,7 +3048,7 @@ begin
end;
function TCodeToolManager.FindSourceNameReferences(TargetFilename: string; Files: TStringList;
SkipComments: boolean; out ListOfSrcNameRefs: TObjectList): boolean;
SkipComments: boolean; out ListOfSrcNameRefs: TObjectList; WithDuplicates: boolean): boolean;
var
i, j, InFilenameCleanPos: Integer;
Filename, Dir, TargetUnitName, InFilename, LocalSrcName: String;
@ -3057,6 +3057,8 @@ var
DirCache: TCTDirectoryCache;
TreeOfPCodeXYPosition: TAVLTree;
Param: TSrcNameRefs;
Node, NextNode: TAVLTreeNode;
CodeXYPos: PCodeXYPosition;
begin
{$IFDEF VerboseFindSourceNameReferences}
debugln(['TCodeToolManager.FindReferencesInFiles TargetFile="',TargetFilename,'" FileCount=',Files.Count,' SkipComments=',SkipComments]);
@ -3074,7 +3076,7 @@ begin
'','.','..': continue; // invalid filename
end;
{$IFDEF VerboseFindSourceNameReferences}
debugln(['TCodeToolManager.FindReferencesInFiles File ',Filename]);
debugln(['TCodeToolManager.FindReferencesInFiles File ',i,'/',Files.Count,' ',Filename]);
{$ENDIF}
j:=i-1;
while (j>=0) and (CompareFilenames(Filename,Files[j])<>0) do dec(j);
@ -3137,6 +3139,22 @@ begin
FreeTreeOfPCodeXYPosition(TreeOfPCodeXYPosition);
continue;
end;
if (not WithDuplicates) and (ListOfSrcNameRefs<>nil) then begin
// elimnate duplicates
for j:=0 to ListOfSrcNameRefs.Count-1 do begin
Param:=TSrcNameRefs(ListOfSrcNameRefs[j]);
if Param.TreeOfPCodeXYPosition=nil then continue;
Node:=TreeOfPCodeXYPosition.FindLowest;
while Node<>nil do begin
NextNode:=TreeOfPCodeXYPosition.FindSuccessor(Node);
CodeXYPos:=PCodeXYPosition(Node.Data);
if Param.TreeOfPCodeXYPosition.Find(CodeXYPos)<>nil then
TreeOfPCodeXYPosition.Delete(Node);
Node:=NextNode;
end;
end;
end;
{$IFDEF VerboseFindSourceNameReferences}
debugln(['TCodeToolManager.FindSourceNameReferences SrcName="',LocalSrcName,'" Count=',TreeOfPCodeXYPosition.Count]);
{$ENDIF}

View File

@ -10,9 +10,11 @@ unit TestRefactoring;
interface
uses
Classes, SysUtils, CodeToolManager, CodeCache, CodeTree, BasicCodeTools, CTUnitGraph,
FindDeclarationTool, ChangeDeclarationTool, LazLogger, LazFileUtils, AVL_Tree, Contnrs, fpcunit,
testregistry, TestFinddeclaration;
Classes, SysUtils, Contnrs, fpcunit, AVL_Tree,
LazLogger, LazFileUtils, testregistry,
CodeToolManager, CodeCache, CodeTree, BasicCodeTools, CTUnitGraph,
FindDeclarationTool, ChangeDeclarationTool, TestGlobals,
TestFinddeclaration;
const
ExplodeWithMarker = 'explodewith:';
@ -24,7 +26,9 @@ type
protected
procedure RenameReferences(NewIdentifier: string; const Flags: TFindRefsFlags = []);
procedure RenameSourceName(NewName, NewFilename: string);
procedure RenameUsedUnitRefs(UsedUnit: TCodeBuffer; NewName, NewFilename: string);
procedure RenameSourceName(NewName, NewFilename: string; const AddFiles: array of string);
procedure RenameUsedUnitRefs(UsedUnit: TCodeBuffer; NewName, NewFilename: string); // only in Code, not in UsedUnit
procedure RenameUsedUnitRefs(UsedUnit: TCodeBuffer; NewName, NewFilename: string; const AddFiles: array of string);
procedure CheckDiff(CurCode: TCodeBuffer; const ExpLines: array of string);
end;
@ -68,6 +72,10 @@ type
procedure TestRenameProgramName_DottedShortenEnd;
procedure TestRenameProgramName_ToraToraTora;
// rename unit
procedure TestRenameUnitName_IncludeUsedTwiceInOneUnit;
procedure TestRenameUnitName_IncludeUsedInTwoUnits;
// rename uses
procedure TestUseOmittedNamespace;
procedure TestRenameUsedUnit_Amp;
@ -171,9 +179,16 @@ begin
end;
procedure TCustomTestRefactoring.RenameSourceName(NewName, NewFilename: string);
begin
RenameSourceName(NewName,NewFilename,[]);
end;
procedure TCustomTestRefactoring.RenameSourceName(NewName, NewFilename: string;
const AddFiles: array of string);
var
Files: TStringList;
ListOfSrcNameRefs: TObjectList;
i: Integer;
begin
// create the file list
ListOfSrcNameRefs:=nil;
@ -181,6 +196,9 @@ begin
try
// search pascal source references in Code
Files.Add(Code.Filename);
for i:=0 to length(AddFiles)-1 do
Files.Add(AddFiles[i]);
if not CodeToolBoss.FindSourceNameReferences(Code.Filename,Files,false,ListOfSrcNameRefs) then
begin
Fail('CodeToolBoss.FindSourceNameReferences failed File='+Code.Filename);
@ -221,6 +239,36 @@ begin
end;
end;
procedure TCustomTestRefactoring.RenameUsedUnitRefs(UsedUnit: TCodeBuffer; NewName,
NewFilename: string; const AddFiles: array of string);
var
Files: TStringList;
ListOfSrcNameRefs: TObjectList;
i: Integer;
begin
// create the file list
ListOfSrcNameRefs:=nil;
Files:=TStringList.Create;
try
// search pascal source references in Code
Files.Add(UsedUnit.Filename);
Files.Add(Code.Filename);
for i:=0 to length(AddFiles)-1 do
Files.Add(AddFiles[i]);
if not CodeToolBoss.FindSourceNameReferences(UsedUnit.Filename,Files,false,ListOfSrcNameRefs) then
begin
Fail('CodeToolBoss.FindSourceNameReferences failed File='+Code.Filename);
end;
// rename
if not CodeToolBoss.RenameSourceNameReferences(UsedUnit.Filename,NewFilename,NewName,ListOfSrcNameRefs)
then
Fail('CodeToolBoss.RenameSourceNameReferences failed');
finally
ListOfSrcNameRefs.Free;
Files.Free;
end;
end;
procedure TCustomTestRefactoring.CheckDiff(CurCode: TCodeBuffer;
const ExpLines: array of string);
var
@ -1481,6 +1529,137 @@ begin
'']);
end;
procedure TTestRefactoring.TestRenameUnitName_IncludeUsedTwiceInOneUnit;
var
RedInc: TCodeBuffer;
begin
RedInc:=CodeToolBoss.CreateFile('red.inc');
try
RedInc.Source:=
'{$IFDEF EnableIntf}'+LineEnding
+'function Fly: Test1.TBird;'+LineEnding
+'{$ENDIF}'+LineEnding
+'{$IFDEF EnableImpl}'+LineEnding
+'function Fly: Test1.TBird;'+LineEnding
+'begin'+LineEnding
+' Test1.Ant:=test1.ant;'+LineEnding
+'end;'+LineEnding
+'{$ENDIF}'+LineEnding;
Add([
'unit test1;',
'{$mode objfpc}{$H+}',
'interface',
'type TAnt = word;',
'{$define EnableIntf}',
'{$i red.inc}',
'{$undefine EnableIntf}',
'implementation',
'{$define EnableImpl}',
'{$i red.inc}',
'{$undefine EnableIntf}',
'end.',
'']);
RenameSourceName('&End','End.pas');
CheckDiff(Code,[
'unit &End;',
'{$mode objfpc}{$H+}',
'interface',
'type TAnt = word;',
'{$define EnableIntf}',
'{$i red.inc}',
'{$undefine EnableIntf}',
'implementation',
'{$define EnableImpl}',
'{$i red.inc}',
'{$undefine EnableIntf}',
'end.',
'']);
CheckDiff(RedInc,[
'{$IFDEF EnableIntf}',
'function Fly: &End.TBird;',
'{$ENDIF}',
'{$IFDEF EnableImpl}',
'function Fly: &End.TBird;',
'begin',
' &End.Ant:=&End.ant;',
'end;',
'{$ENDIF}']);
finally
RedInc.IsDeleted:=true;
end;
end;
procedure TTestRefactoring.TestRenameUnitName_IncludeUsedInTwoUnits;
var
RedInc, RedGreenUnit: TCodeBuffer;
begin
RedInc:=CodeToolBoss.CreateFile('red.inc');
RedGreenUnit:=CodeToolBoss.CreateFile('red.green.pas');
try
RedInc.Source:=LinesToStr([
'function Fly: Red.Green.TAnt;',
'begin',
' red.green.Ant:=3;',
'end;']);
RedGreenUnit.Source:=LinesToStr([
'unit Red.Green;',
'interface',
'type TAnt = word;',
'var Ant: TAnt;',
'implementation',
'{$I red.inc}',
'var Hop: red.green.TAnt;',
'end.']);
Add([
'unit test1;',
'{$mode objfpc}{$H+}',
'interface',
'uses Red.Green;',
'implementation',
'{$I red.inc}',
'begin',
' red.green.ant:=2;',
'end.',
'']);
RenameUsedUnitRefs(RedGreenUnit,'&End','end.pas',[]);
CheckDiff(Code,[
'unit test1;',
'{$mode objfpc}{$H+}',
'interface',
'uses &End;',
'implementation',
'{$I red.inc}',
'begin',
' &End.ant:=2;',
'end.',
'']);
CheckDiff(RedGreenUnit,[
'unit &End;',
'interface',
'type TAnt = word;',
'var Ant: TAnt;',
'implementation',
'{$I red.inc}',
'var Hop: &End.TAnt;',
'end.']);
CheckDiff(RedInc,[
'function Fly: &End.TAnt;',
'begin',
' &End.Ant:=3;',
'end;']);
finally
RedInc.IsDeleted:=true;
RedGreenUnit.IsDeleted:=true;
end;
end;
procedure TTestRefactoring.TestUseOmittedNamespace;
procedure t(const OldShort, OldFull, NewFull, Expected: string);