implemented Refactoring Tool: Find Identfier References

git-svn-id: trunk@6035 -
This commit is contained in:
mattias 2004-09-20 20:22:13 +00:00
parent 76c2c59c99
commit 62665cfd40
15 changed files with 713 additions and 250 deletions

View File

@ -67,6 +67,7 @@ procedure IndentText(const Source: string; Indent, TabWidth: integer;
// identifiers
procedure GetIdentStartEndAtPosition(const Source:string; Position:integer;
var IdentStart,IdentEnd:integer);
function GetIdentStartPosition(const Source:string; Position:integer): integer;
function GetIdentLen(Identifier: PChar): integer;
function GetIdentifier(Identifier: PChar): string;
function FindNextIdentifier(const Source: string; StartPos, MaxPos: integer
@ -1287,6 +1288,16 @@ begin
inc(IdentEnd);
end;
function GetIdentStartPosition(const Source: string; Position: integer
): integer;
begin
Result:=Position;
if (Result<1) or (Result>length(Source)) then exit;
while (Result>1)
and (IsIdChar[Source[Result-1]]) do
dec(Result);
end;
function GetIdentLen(Identifier: PChar): integer;
begin
Result:=0;

View File

@ -112,7 +112,7 @@ type
function InitResourceTool: boolean;
procedure ClearPositions;
function GetCodeToolForSource(Code: TCodeBuffer;
ExceptionOnError: boolean): TCustomCodeTool;
GoToMainCode, ExceptionOnError: boolean): TCustomCodeTool;
procedure SetAbortable(const AValue: boolean);
procedure SetAddInheritedCodeToOverrideMethod(const AValue: boolean);
procedure SetCheckFilesOnDisk(NewValue: boolean);
@ -126,7 +126,7 @@ type
procedure AfterApplyingChanges;
function HandleException(AnException: Exception): boolean;
function OnGetCodeToolForBuffer(Sender: TObject;
Code: TCodeBuffer): TFindDeclarationTool;
Code: TCodeBuffer; GoToMainCode: boolean): TFindDeclarationTool;
procedure OnToolSetWriteLock(Lock: boolean);
procedure OnToolGetWriteLockInfo(var WriteLockIsSet: boolean;
var WriteLockStep: integer);
@ -236,6 +236,10 @@ type
// data function
procedure FreeListOfPCodeXYPosition(var List: TList);
procedure FreeTreeOfPCodeXYPosition(var Tree: TAVLTree);
function CreateTreeOfPCodeXYPosition: TAVLTree;
procedure AddListToTreeOfPCodeXYPosition(SrcList: TList; DestTree: TAVLTree;
ClearList, CreateCopies: boolean);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -999,6 +1003,55 @@ begin
end;
end;
procedure TCodeToolManager.FreeTreeOfPCodeXYPosition(var Tree: TAVLTree);
var
ANode: TAVLTreeNode;
CursorPos: PCodeXYPosition;
begin
if Tree=nil then exit;
ANode:=Tree.FindLowest;
while ANode<>nil do begin
CursorPos:=PCodeXYPosition(ANode.Data);
if CursorPos<>nil then
Dispose(CursorPos);
ANode:=Tree.FindSuccessor(ANode);
end;
Tree.Free;
end;
function TCodeToolManager.CreateTreeOfPCodeXYPosition: TAVLTree;
begin
Result:=TAVLTree.Create(@CompareCodeXYPositions);
end;
procedure TCodeToolManager.AddListToTreeOfPCodeXYPosition(SrcList: TList;
DestTree: TAVLTree; ClearList, CreateCopies: boolean);
var
i: Integer;
CodePos: PCodeXYPosition;
NewCodePos: PCodeXYPosition;
begin
if SrcList=nil then exit;
for i:=SrcList.Count-1 downto 0 do begin
CodePos:=PCodeXYPosition(SrcList[i]);
if DestTree.Find(CodePos)=nil then begin
// new position -> add
if CreateCopies and (not ClearList) then begin
// list items should be kept and copies should be added to the tree
New(NewCodePos);
NewCodePos^:=CodePos^;
end else
NewCodePos:=CodePos;
DestTree.Add(NewCodePos);
end else if ClearList then begin
// position alread exists and items should be deleted
Dispose(NewCodePos);
end;
end;
if ClearList then
SrcList.Clear;
end;
function TCodeToolManager.Explore(Code: TCodeBuffer;
var ACodeTool: TCodeTool; WithStatements: boolean): boolean;
begin
@ -1032,7 +1085,7 @@ begin
FErrorMsg:=Format(ctsNoScannerFound,[MainCode.Filename]);
exit;
end;
FCurCodeTool:=TCodeTool(GetCodeToolForSource(MainCode,true));
FCurCodeTool:=TCodeTool(GetCodeToolForSource(MainCode,false,true));
FCurCodeTool.ErrorPosition.Code:=nil;
{$IFDEF CTDEBUG}
DebugLn('[TCodeToolManager.InitCurCodeTool] ',Code.Filename,' ',dbgs(Code.SourceLength));
@ -1392,7 +1445,7 @@ begin
CursorPos.Y:=NewY;
CursorPos.Code:=NewCode;
{$IFDEF CTDEBUG}
DebugLn('TCodeToolManager.FindReferences B ',dbgs(FCurCodeTool.Scanner<>nil));
DebugLn('TCodeToolManager.FindReferences B ',dbgs(FCurCodeTool.Scanner<>nil),' x=',dbgs(CursorPos.X),' y=',dbgs(CursorPos.Y),' ',CursorPos.Code.Filename);
{$ENDIF}
try
Result:=FCurCodeTool.FindReferences(CursorPos,SkipComments,
@ -2921,7 +2974,7 @@ begin
end;
function TCodeToolManager.GetCodeToolForSource(Code: TCodeBuffer;
ExceptionOnError: boolean): TCustomCodeTool;
GoToMainCode, ExceptionOnError: boolean): TCustomCodeTool;
// return a codetool for the source
begin
Result:=nil;
@ -2931,6 +2984,8 @@ begin
+'internal error: Code=nil');
exit;
end;
if GoToMainCode then
Code:=GetMainCode(Code);
Result:=FindCodeToolForSource(Code);
if Result=nil then begin
CreateScanner(Code);
@ -2977,14 +3032,14 @@ begin
end;
function TCodeToolManager.OnGetCodeToolForBuffer(Sender: TObject;
Code: TCodeBuffer): TFindDeclarationTool;
Code: TCodeBuffer; GoToMainCode: boolean): TFindDeclarationTool;
begin
{$IFDEF CTDEBUG}
DebugLn('[TCodeToolManager.OnGetCodeToolForBuffer]'
,' Sender=',TCustomCodeTool(Sender).MainFilename
,' Code=',Code.Filename);
{$ENDIF}
Result:=TFindDeclarationTool(GetCodeToolForSource(Code,true));
Result:=TFindDeclarationTool(GetCodeToolForSource(Code,GoToMainCode,true));
end;
procedure TCodeToolManager.ActivateWriteLock;

View File

@ -650,8 +650,8 @@ var
{$ENDIF}
ProcClassName:=ExtractClassNameOfProcNode(ProcNode);
if ProcClassName='' then exit;
ProcClassNode:=FindClassNodeInUnit(UpperCaseStr(ProcClassName),
true,false,true);
ProcClassNode:=FindClassNodeInUnit(ProcClassName,
true,false,false,true);
if ProcClassNode=nil then exit;
ProcClassName:=ExtractClassName(ProcClassNode,false);
end;

View File

@ -412,7 +412,7 @@ type
TOnFindUsedUnit = function(SrcTool: TFindDeclarationTool;
const TheUnitName, TheUnitInFilename: string): TCodeBuffer of object;
TOnGetCodeToolForBuffer = function(Sender: TObject;
Code: TCodeBuffer): TFindDeclarationTool of object;
Code: TCodeBuffer; GoToMainCode: boolean): TFindDeclarationTool of object;
TFindDeclarationInput = record
Flags: TFindDeclarationFlags;
@ -666,7 +666,7 @@ type
var ListOfPCodeXYPosition: TList): boolean;
function FindReferences(const CursorPos: TCodeXYPosition;
SkipComments: boolean; var ListOfPCodeXYPosition: TList): boolean;
function CleanPosIsDeclaration(CleanPos: integer;
function CleanPosIsDeclarationIdentifier(CleanPos: integer;
Node: TCodeTreeNode): boolean;
function JumpToNode(ANode: TCodeTreeNode;
@ -1018,11 +1018,13 @@ begin
CursorNode:=BuildSubTreeAndFindDeepestNodeAtPos(Tree.Root,CleanCursorPos,
true);
if (fsfFindMainDeclaration in SearchSmartFlags)
and CleanPosIsDeclaration(CleanCursorPos,CursorNode)
and CleanPosIsDeclarationIdentifier(CleanCursorPos,CursorNode)
then begin
NewTool:=Self;
NewNode:=CursorNode;
Result:=JumpToNode(CursorNode,NewPos,NewTopLine,false);
CleanCursorPos:=GetIdentStartPosition(Src,CleanCursorPos);
Result:=JumpToCleanPos(CleanCursorPos,CleanCursorPos,CleanCursorPos,
NewPos,NewTopLine,false);
exit;
end;
CleanPosInFront:=CursorNode.StartPos;
@ -2882,8 +2884,9 @@ function TFindDeclarationTool.FindReferences(const CursorPos: TCodeXYPosition;
var
Identifier: string;
DeclarationTool: TFindDeclarationTool;
CleanDeclCursorPos: integer;
DeclarationNode: TCodeTreeNode;
CleanDeclCursorPos: integer;
AliasDeclarationNode: TCodeTreeNode;
StartPos: Integer;
Params: TFindDeclarationParams;
PosTree: TAVLTree; // tree of PChar positions in Src
@ -2891,53 +2894,8 @@ var
ReferencePos: TCodeXYPosition;
MaxPos: Integer;
CursorNode: TCodeTreeNode;
Found: Boolean;
function FindNextIdentifier(var StartPos: integer): boolean;
var
p: PChar;
LastChar: Char;
CurChar: Char;
MaxP: PChar;
begin
Result:=false;
if SkipComments then begin
// search only in tokens
MoveCursorToCleanPos(StartPos);
repeat
ReadNextAtom;
if CurPos.StartPos>=MaxPos then exit;
if CompareIdentifiers(PChar(Identifier),@Src[CurPos.StartPos])=0 then
begin
Result:=true;
exit;
end;
until false;
end else begin
// search in clean source
p:=@Src[StartPos];
LastChar:=#0;
MaxP:=@Src[MaxPos-1];
while p<=MaxP do begin
CurChar:=p^;
if (CurChar=Identifier[1]) and (not IsIdentChar[LastChar]) then begin
if CompareIdentifiers(PChar(Identifier),p)=0 then begin
//debugln(' FindNextIdentifier ',Identifier,' ',GetIdentifier(p));
Result:=true;
break;
end;
end else if CurChar='''' then begin
// skip string constants
repeat
inc(p);
until (p^ in ['''',#10,#13]) or (p>MaxP);
end;
LastChar:=CurChar;
inc(p);
end;
StartPos:=p-PChar(Src)+1;
end;
end;
procedure AddReference;
var
p: PChar;
@ -2961,20 +2919,197 @@ var
//debugln('TFindDeclarationTool.FindReferences.AddCodePosition line=',dbgs(NewCodePos.Y),' col=',dbgs(NewCodePos.X));
end;
begin
Result:=false;
ListOfPCodeXYPosition:=nil;
Params:=nil;
PosTree:=nil;
procedure ReadIdentifier(IsComment: boolean);
var
IdentEndPos: LongInt;
begin
IdentEndPos:=StartPos;
while (IdentEndPos<=MaxPos) and (IsIdentChar[Src[IdentEndPos]]) do
inc(IdentEndPos);
//debugln('ReadIdentifier ',copy(Src,StartPos,IdentEndPos-StartPos));
if (IdentEndPos-StartPos=length(Identifier))
and (CompareIdentifiers(PChar(Identifier),@Src[StartPos])=0)
and (IsComment or (not SkipComments)) then begin
debugln('Identifier with same name found at: ',dbgs(StartPos),' ',GetIdentifier(@Src[StartPos]),' CleanDeclCursorPos=',dbgs(CleanDeclCursorPos),' ',dbgs(MaxPos));
if CleanPosToCaret(StartPos,ReferencePos) then
debugln(' x=',dbgs(ReferencePos.X),' y=',dbgs(ReferencePos.Y),' ',ReferencePos.Code.Filename);
ActivateGlobalWriteLock;
try
BuildTree(false);
CursorNode:=BuildSubTreeAndFindDeepestNodeAtPos(Tree.Root,StartPos,true);
debugln(' CursorNode=',CursorNode.DescAsString,' ',dbgs(CursorNode.SubDesc and ctnsForwardDeclaration));
// find declaration node and identifier
if (DeclarationTool=Self)
and ((StartPos=CleanDeclCursorPos) or (CursorNode=AliasDeclarationNode))
then
// declaration itself found
AddReference
else if CleanPosIsDeclarationIdentifier(StartPos,CursorNode) then
// this identifier is another declaration with the same name
else begin
// find declaration
if Params=nil then
Params:=TFindDeclarationParams.Create
else
Params.Clear;
Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors,
fdfExceptionOnNotFound];
Params.ContextNode:=CursorNode;
//debugln(copy(Src,Params.ContextNode.StartPos,200));
Params.SetIdentifier(Self,@Src[StartPos],@CheckSrcIdentifier);
if not IsComment then begin
// search identifier
Found:=FindDeclarationOfIdentAtCursor(Params);
end else begin
// search identifier in comment -> if not found, this is no bug
// => silently ignore
try
Found:=FindDeclarationOfIdentAtCursor(Params);
except
on E: ECodeToolError do ;
end;
end;
if Found and (Params.NewNode<>nil) then begin
if (Params.NewNode<>nil) and (Params.NewNode.Desc=ctnProcedure)
and (Params.NewNode.FirstChild<>nil)
and (Params.NewNode.FirstChild.Desc=ctnProcedureHead) then begin
// Instead of jumping to the procedure keyword,
// jump to the procedure name
Params.NewNode:=Params.NewNode.FirstChild;
Params.NewCleanPos:=Params.NewNode.StartPos;
end;
debugln('Context=',Params.NewNode.DescAsString,' ',dbgs(Params.NewNode.StartPos),' ',dbgs(DeclarationNode.StartPos));
if (Params.NewNode=DeclarationNode)
or (Params.NewNode=AliasDeclarationNode) then
AddReference;
end;
end;
end;
StartPos:=IdentEndPos;
end;
procedure SearchIdentifiers;
var
CommentLvl: Integer;
InStrConst: Boolean;
//CommentStart: LongInt;
begin
StartPos:=1;
while StartPos<=MaxPos do begin
case Src[StartPos] of
'{': // pascal comment
begin
//CommentStart:=StartPos;
inc(StartPos);
CommentLvl:=1;
InStrConst:=false;
while StartPos<=MaxPos do begin
case Src[StartPos] of
'{': if Scanner.NestedComments then inc(CommentLvl);
'}':
begin
dec(CommentLvl);
if CommentLvl=0 then break;
end;
'a'..'z','A'..'Z','_':
if not InStrConst then begin
ReadIdentifier(true);
dec(StartPos);
end;
'''':
InStrConst:=not InStrConst;
end;
inc(StartPos);
end;
inc(StartPos);
//debugln(StartPos,' ',copy(Src,CommentStart,StartPos-CommentStart));
end;
'/': // Delphi comment
if (Src[StartPos+1]<>'/') then begin
inc(StartPos);
end else begin
inc(StartPos,2);
InStrConst:=false;
while (StartPos<=MaxPos) do begin
case Src[StartPos] of
#10,#13:
break;
'a'..'z','A'..'Z','_':
if not InStrConst then begin
ReadIdentifier(true);
dec(StartPos);
end;
'''':
InStrConst:=not InStrConst;
end;
inc(StartPos);
end;
inc(StartPos);
if (StartPos<=MaxPos) and (Src[StartPos] in [#10,#13])
and (Src[StartPos-1]<>Src[StartPos]) then
inc(StartPos);
end;
'(': // turbo pascal comment
if (Src[StartPos+1]<>'*') then begin
inc(StartPos);
end else begin
inc(StartPos,3);
InStrConst:=false;
while (StartPos<=MaxPos) do begin
case Src[StartPos] of
')':
if Src[StartPos-1]='*' then break;
'a'..'z','A'..'Z','_':
if not InStrConst then begin
ReadIdentifier(true);
dec(StartPos);
end;
'''':
InStrConst:=not InStrConst;
end;
inc(StartPos);
end;
inc(StartPos);
end;
'a'..'z','A'..'Z','_':
ReadIdentifier(false);
'''':
begin
// skip string constant
inc(StartPos);
while (StartPos<=MaxPos) do begin
if (not (Src[StartPos] in ['''',#10,#13])) then
inc(StartPos)
else begin
inc(StartPos);
break;
end;
end;
end;
else
inc(StartPos);
end;
end;
end;
function FindDeclarationNode: boolean;
const
JumpToProcAttr = [phpInUpperCase,phpWithoutClassName,phpWithVarModifiers];
var
ProcNode: TCodeTreeNode;
begin
Result:=false;
// find the main declaration node and identifier
DeclarationTool:=nil;
if Assigned(FOnGetCodeToolForBuffer) then
DeclarationTool:=FOnGetCodeToolForBuffer(Self,CursorPos.Code)
DeclarationTool:=FOnGetCodeToolForBuffer(Self,CursorPos.Code,true)
else if CursorPos.Code=TObject(Scanner.MainCode) then
DeclarationTool:=Self;
if DeclarationTool=nil then begin
@ -2988,52 +3123,72 @@ begin
Identifier:=DeclarationTool.ExtractIdentifier(CleanDeclCursorPos);
if Identifier='' then exit;
// search identifiers
MaxPos:=Tree.FindLastPosition;
StartPos:=1;
while FindNextIdentifier(StartPos) do begin
//debugln('Identifier with same name found at: ',dbgs(StartPos),' ',GetIdentifier(@Src[StartPos]),' CleanDeclCursorPos=',dbgs(CleanDeclCursorPos),' ',dbgs(MaxPos));
//if CleanPosToCaret(StartPos,ReferencePos) then
//debugln(' x=',dbgs(ReferencePos.X),' y=',dbgs(ReferencePos.Y),' ',ReferencePos.Code.Filename);
// find alias declaration node
debugln('FindDeclarationNode DeclarationNode=',DeclarationNode.DescAsString);
AliasDeclarationNode:=nil;
case DeclarationNode.Desc of
CursorNode:=BuildSubTreeAndFindDeepestNodeAtPos(Tree.Root,StartPos,true);
//debugln(' CursorNode=',CursorNode.DescAsString,' ',dbgs(CursorNode.SubDesc and ctnsForwardDeclaration));
if (DeclarationTool=Self) and (StartPos=CleanDeclCursorPos) then
// declaration itself found
AddReference
else if CleanPosIsDeclaration(StartPos,CursorNode) then
// this identifier is another declaration with the same name
else begin
// find declaration
if Params=nil then
Params:=TFindDeclarationParams.Create
else
Params.Clear;
Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors,
fdfExceptionOnNotFound];
Params.ContextNode:=CursorNode;
//debugln(copy(Src,Params.ContextNode.StartPos,200));
Params.SetIdentifier(Self,@Src[StartPos],@CheckSrcIdentifier);
if FindDeclarationOfIdentAtCursor(Params)
and (Params.NewNode<>nil) then begin
if (Params.NewNode<>nil) and (Params.NewNode.Desc=ctnProcedure)
and (Params.NewNode.FirstChild<>nil)
and (Params.NewNode.FirstChild.Desc=ctnProcedureHead) then begin
// Instead of jumping to the procedure keyword,
// jump to the procedure name
Params.NewNode:=Params.NewNode.FirstChild;
Params.NewCleanPos:=Params.NewNode.StartPos;
ctnProcedure:
AliasDeclarationNode:=FindCorrespondingProcNode(DeclarationNode,
JumpToProcAttr);
ctnProcedureHead:
AliasDeclarationNode:=FindCorrespondingProcNode(DeclarationNode.Parent,
JumpToProcAttr);
ctnVarDefinition:
if DeclarationNode.HasParentOfType(ctnProcedureHead) then begin
ProcNode:=DeclarationNode.GetNodeOfType(ctnProcedure);
// search alias for parameter
ProcNode:=FindCorrespondingProcNode(ProcNode,JumpToProcAttr);
if ProcNode<>nil then begin
BuildSubTreeForProcHead(ProcNode);
AliasDeclarationNode:=ProcNode;
while (AliasDeclarationNode<>nil) do begin
if AliasDeclarationNode.Desc
in [ctnProcedure,ctnProcedureHead,ctnParameterList]
then
AliasDeclarationNode:=AliasDeclarationNode.FirstChild
else begin
if CompareIdentifiers(PChar(identifier),
@Src[AliasDeclarationNode.StartPos])=0 then break;
AliasDeclarationNode:=AliasDeclarationNode.NextBrother;
end;
end;
//debugln('Context=',Params.NewNode.DescAsString,' ',dbgs(Params.NewNode.StartPos),' ',dbgs(DeclarationNode.StartPos));
if (Params.NewNode=DeclarationNode) then
AddReference;
end;
end;
inc(StartPos,length(Identifier));
end;
if (AliasDeclarationNode<>nil) and (AliasDeclarationNode.Desc=ctnProcedure)
and (AliasDeclarationNode.FirstChild<>nil)
and (AliasDeclarationNode.FirstChild.Desc=ctnProcedureHead) then
AliasDeclarationNode:=AliasDeclarationNode.FirstChild;
if AliasDeclarationNode<>nil then begin
debugln('FindDeclarationNode AliasDeclarationNode=',AliasDeclarationNode.DescAsString);
end;
Result:=true;
end;
begin
Result:=false;
debugln('FindReferences CursorPos=',CursorPos.Code.Filename,' x=',dbgs(CursorPos.X),' y=',dbgs(CursorPos.Y),' SkipComments=',dbgs(SkipComments));
ListOfPCodeXYPosition:=nil;
Params:=nil;
PosTree:=nil;
ActivateGlobalWriteLock;
try
BuildTree(false);
// find declaration nodes and identifier
if not FindDeclarationNode then exit;
// search identifiers
MaxPos:=Tree.FindLastPosition;
if MaxPos>SrcLen then MaxPos:=SrcLen;
SearchIdentifiers;
// create the reference list
if PosTree<>nil then begin
AVLNode:=PosTree.FindHighest;
@ -3054,13 +3209,13 @@ begin
end;
{-------------------------------------------------------------------------------
function TFindDeclarationTool.CleanPosIsDeclaration(CleanPos: integer;
function TFindDeclarationTool.CleanPosIsDeclarationIdentifier(CleanPos: integer;
Node: TCodeTreeNode): boolean;
Node should be the deepest node at CleanPos, and all sub trees built.
See BuildSubTree
-------------------------------------------------------------------------------}
function TFindDeclarationTool.CleanPosIsDeclaration(CleanPos: integer;
function TFindDeclarationTool.CleanPosIsDeclarationIdentifier(CleanPos: integer;
Node: TCodeTreeNode): boolean;
function InNodeIdentifier: boolean;
@ -3085,7 +3240,7 @@ begin
if Node=nil then exit;
case Node.Desc of
ctnTypeDefinition,ctnVarDefinition,ctnConstDefinition:
ctnTypeDefinition,ctnVarDefinition,ctnConstDefinition,ctnEnumIdentifier:
begin
if NodeIsForwardDeclaration(Node) then exit;
Result:=InNodeIdentifier;
@ -3096,7 +3251,7 @@ begin
ctnBeginBlock,ctnClass,ctnProcedure:
if (Node.SubDesc and ctnsForwardDeclaration)>0 then
RaiseException('TFindDeclarationTool.CleanPosIsDeclaration Node not expanded');
RaiseException('TFindDeclarationTool.CleanPosIsDeclarationIdentifier Node not expanded');
end;
end;
@ -3835,7 +3990,7 @@ begin
' NewCode=',NewCode.Filename);
{$ENDIF}
if Assigned(FOnGetCodeToolForBuffer) then
Result:=FOnGetCodeToolForBuffer(Self,NewCode)
Result:=FOnGetCodeToolForBuffer(Self,NewCode,false)
else if NewCode=TCodeBuffer(Scanner.MainCode) then
Result:=Self;
end;
@ -4010,7 +4165,7 @@ begin
' NewCode=',NewCode.Filename,' IgnoreUsedUnits=',dbgs(fdfIgnoreUsedUnits in Params.Flags));
{$ENDIF}
if Assigned(FOnGetCodeToolForBuffer) then begin
NewCodeTool:=FOnGetCodeToolForBuffer(Self,NewCode);
NewCodeTool:=FOnGetCodeToolForBuffer(Self,NewCode,false);
if NewCodeTool=nil then begin
CurPos.StartPos:=-1;
RaiseExceptionInstance(

View File

@ -37,8 +37,9 @@ uses
{$IFDEF MEM_CHECK}
MemCheck,
{$ENDIF}
Classes, SysUtils, CodeToolsStrConsts, CodeTree, CodeAtom, CustomCodeTool,
PascalParserTool, KeywordFuncLists, BasicCodeTools, LinkScanner, AVL_Tree;
Classes, SysUtils, FileProcs, CodeToolsStrConsts, CodeTree, CodeAtom,
CustomCodeTool, PascalParserTool, KeywordFuncLists, BasicCodeTools,
LinkScanner, AVL_Tree;
type
TPascalReaderTool = class(TPascalParserTool)
@ -84,6 +85,8 @@ type
function GetProcNameIdentifier(ProcNode: TCodeTreeNode): PChar;
function FindProcNode(StartNode: TCodeTreeNode; const AProcHead: string;
Attr: TProcHeadAttributes): TCodeTreeNode;
function FindCorrespondingProcNode(ProcNode: TCodeTreeNode;
Attr: TProcHeadAttributes): TCodeTreeNode;
function FindProcBody(ProcNode: TCodeTreeNode): TCodeTreeNode;
procedure MoveCursorToFirstProcSpecifier(ProcNode: TCodeTreeNode);
function MoveCursorToProcSpecifier(ProcNode: TCodeTreeNode;
@ -100,16 +103,17 @@ type
function ExtractClassInheritance(ClassNode: TCodeTreeNode;
Attr: TProcHeadAttributes): string;
function FindClassNode(StartNode: TCodeTreeNode;
const UpperClassName: string;
const AClassName: string;
IgnoreForwards, IgnoreNonForwards: boolean): TCodeTreeNode;
function FindClassSection(ClassNode: TCodeTreeNode;
NodeDesc: TCodeTreeNodeDesc): TCodeTreeNode;
function FindLastClassSection(ClassNode: TCodeTreeNode;
NodeDesc: TCodeTreeNodeDesc): TCodeTreeNode;
function FindClassNodeInInterface(const UpperClassName: string;
IgnoreForwards, IgnoreNonForwards, ErrorOnNotFound: boolean): TCodeTreeNode;
function FindClassNodeInUnit(const UpperClassName: string;
function FindClassNodeInInterface(const AClassName: string;
IgnoreForwards, IgnoreNonForwards, ErrorOnNotFound: boolean): TCodeTreeNode;
function FindClassNodeInUnit(const AClassName: string;
IgnoreForwards, IgnoreNonForwards, IgnoreImplementation,
ErrorOnNotFound: boolean): TCodeTreeNode;
function FindFirstIdentNodeInClass(ClassNode: TCodeTreeNode): TCodeTreeNode;
function ClassSectionNodeStartsWithWord(ANode: TCodeTreeNode): boolean;
@ -534,6 +538,54 @@ begin
end;
end;
function TPascalReaderTool.FindCorrespondingProcNode(ProcNode: TCodeTreeNode;
Attr: TProcHeadAttributes): TCodeTreeNode;
var
ClassNode: TCodeTreeNode;
StartNode: TCodeTreeNode;
ProcHead: String;
begin
Result:=nil;
// get ctnProcedure
//debugln('TPascalReaderTool.FindCorrespondingProcNode A');
if (ProcNode=nil) then exit;
if ProcNode.Desc=ctnProcedureHead then begin
ProcNode:=ProcNode.Parent;
if (ProcNode=nil) then exit;
end;
if ProcNode.Desc<>ctnProcedure then exit;
// check proc kind
//debugln('TPascalReaderTool.FindCorrespondingProcNode B');
ClassNode:=ProcNode.GetNodeOfType(ctnClass);
if ClassNode<>nil then begin
//debugln('TPascalReaderTool.FindCorrespondingProcNode C');
// in a class definition -> search method body
StartNode:=ClassNode.GetNodeOfType(ctnTypeSection)
end else if NodeIsMethodBody(ProcNode) then begin
//debugln('TPascalReaderTool.FindCorrespondingProcNode D');
// in a method body -> search class
StartNode:=FindClassNodeInUnit(ExtractClassNameOfProcNode(ProcNode),true,
false,false,true);
BuildSubTreeForClass(StartNode);
while (StartNode<>nil)
and (StartNode.Desc in [ctnClass,ctnClassInterface]+AllClassSections) do
StartNode:=StartNode.FirstChild;
//debugln('TPascalReaderTool.FindCorrespondingProcNode D2 ',StartNode.DescAsString);
end else
// else: search on same lvl
StartNode:=FindFirstNodeOnSameLvl(ProcNode);
if StartNode=nil then exit;
//debugln('TPascalReaderTool.FindCorrespondingProcNode E');
ProcHead:=ExtractProcHead(ProcNode,Attr);
Result:=FindProcNode(StartNode,ProcHead,Attr);
if Result=ProcNode then begin
StartNode:=FindNextNodeOnSameLvl(Result);
Result:=FindProcNode(StartNode,ProcHead,Attr);
end;
end;
function TPascalReaderTool.FindProcBody(ProcNode: TCodeTreeNode
): TCodeTreeNode;
begin
@ -946,18 +998,18 @@ begin
end;
function TPascalReaderTool.FindClassNode(StartNode: TCodeTreeNode;
const UpperClassName: string; IgnoreForwards, IgnoreNonForwards: boolean
const AClassName: string; IgnoreForwards, IgnoreNonForwards: boolean
): TCodeTreeNode;
// search for types on same level,
// with type class and classname = SearchedClassName
var CurClassName: string;
var
ANode, CurClassNode: TCodeTreeNode;
begin
ANode:=StartNode;
Result:=nil;
while (ANode<>nil) do begin
if ANode.Desc=ctnTypeSection then begin
Result:=FindClassNode(ANode.FirstChild,UpperClassName,IgnoreForwards,
Result:=FindClassNode(ANode.FirstChild,AClassName,IgnoreForwards,
IgnoreNonForwards);
if Result<>nil then exit;
end else if ANode.Desc=ctnTypeDefinition then begin
@ -968,10 +1020,8 @@ begin
and (not (IgnoreNonForwards
and ((CurClassNode.SubDesc and ctnsForwardDeclaration)=0)))
then begin
MoveCursorToNodeStart(ANode);
ReadNextAtom;
CurClassName:=GetUpAtom;
if UpperClassName=CurClassName then begin
if CompareIdentifiers(PChar(AClassName),@Src[ANode.StartPos])=0
then begin
Result:=CurClassNode;
exit;
end;
@ -1005,12 +1055,12 @@ begin
end;
function TPascalReaderTool.FindClassNodeInInterface(
const UpperClassName: string; IgnoreForwards, IgnoreNonForwards,
const AClassName: string; IgnoreForwards, IgnoreNonForwards,
ErrorOnNotFound: boolean): TCodeTreeNode;
procedure RaiseClassNotFound;
begin
RaiseExceptionFmt(ctsClassSNotFound, [UpperClassName]);
RaiseExceptionFmt(ctsClassSNotFound, [AClassName]);
end;
begin
@ -1019,20 +1069,24 @@ begin
if Result.Desc=ctnUnit then begin
Result:=Result.NextBrother;
end;
if Result<>nil then
Result:=FindClassNode(Result.FirstChild,UpperClassName,
IgnoreForwards, IgnoreNonForwards);
if Result<>nil then begin
Result:=FindClassNode(Result.FirstChild,AClassName,
IgnoreForwards, IgnoreNonForwards);
if (Result<>nil) and Result.HasParentOfType(ctnImplementation) then
Result:=nil;
end;
end;
if (Result=nil) and ErrorOnNotFound then
RaiseClassNotFound;
end;
function TPascalReaderTool.FindClassNodeInUnit(const UpperClassName: string;
IgnoreForwards, IgnoreNonForwards, ErrorOnNotFound: boolean): TCodeTreeNode;
function TPascalReaderTool.FindClassNodeInUnit(const AClassName: string;
IgnoreForwards, IgnoreNonForwards, IgnoreImplementation,
ErrorOnNotFound: boolean): TCodeTreeNode;
procedure RaiseClassNotFound;
begin
RaiseExceptionFmt(ctsClassSNotFound, [UpperClassName]);
RaiseExceptionFmt(ctsClassSNotFound, [AClassName]);
end;
begin
@ -1041,9 +1095,13 @@ begin
if Result.Desc in [ctnUnit,ctnLibrary,ctnPackage] then begin
Result:=Result.NextBrother;
end;
if Result<>nil then
Result:=FindClassNode(Result.FirstChild,UpperClassName,
IgnoreForwards, IgnoreNonForwards);
if Result<>nil then begin
Result:=FindClassNode(Result.FirstChild,AClassName,
IgnoreForwards, IgnoreNonForwards);
if (Result<>nil) and IgnoreImplementation
and Result.HasParentOfType(ctnImplementation) then
Result:=nil;
end;
end;
if (Result=nil) and ErrorOnNotFound then
RaiseClassNotFound;

View File

@ -3012,8 +3012,10 @@ begin
NearestPos.Code:=nil;
// get both codetools
if not Assigned(OnGetCodeToolForBuffer) then exit;
CursorTool:=TStandardCodeTool(OnGetCodeToolForBuffer(Self,CursorPos.Code));
SectionTool:=TStandardCodeTool(OnGetCodeToolForBuffer(Self,SectionPos.Code));
CursorTool:=
TStandardCodeTool(OnGetCodeToolForBuffer(Self,CursorPos.Code,true));
SectionTool:=
TStandardCodeTool(OnGetCodeToolForBuffer(Self,SectionPos.Code,true));
if (CursorTool=nil) or (SectionTool=nil) then exit;
// get all resourcestring identifiers
IdentTree:=nil;

View File

@ -17,7 +17,6 @@ object FindRenameIdentifierDialog: TFindRenameIdentifierDialog
Caption = 'CurrentGroupBox'
ClientHeight = 55
ClientWidth = 432
DragCursor = 65524
ParentColor = True
TabOrder = 0
Left = 8
@ -38,7 +37,6 @@ object FindRenameIdentifierDialog: TFindRenameIdentifierDialog
Caption = 'NewGroupBox'
ClientHeight = 36
ClientWidth = 432
DragCursor = 65524
ParentColor = True
TabOrder = 1
Left = 8
@ -60,7 +58,6 @@ object FindRenameIdentifierDialog: TFindRenameIdentifierDialog
Anchors = [akTop, akRight]
AutoSize = True
Caption = 'RenameCheckBox'
DragCursor = 65524
OnChange = RenameCheckBoxChange
TabOrder = 1
UseOnChange = True
@ -75,7 +72,6 @@ object FindRenameIdentifierDialog: TFindRenameIdentifierDialog
Caption = 'ScopeGroupBox'
ClientHeight = 187
ClientWidth = 433
DragCursor = 65524
ParentColor = True
TabOrder = 2
Left = 8
@ -87,7 +83,6 @@ object FindRenameIdentifierDialog: TFindRenameIdentifierDialog
Anchors = [akTop, akLeft, akRight]
AutoSize = True
Caption = 'ScopeCommentsCheckBox'
DragCursor = 65524
TabOrder = 0
Left = 6
Height = 23
@ -99,9 +94,10 @@ object FindRenameIdentifierDialog: TFindRenameIdentifierDialog
Caption = 'ScopeRadioGroup'
Enabled = False
Items.Strings = (
'In current Unit'
'In current Project/Package'
'In all open projects and packages'
'in current unit'
'in main project'
'in project/package owning file'
'in all open projects and packages'
)
ParentColor = True
Left = 6
@ -114,7 +110,6 @@ object FindRenameIdentifierDialog: TFindRenameIdentifierDialog
Caption = 'ExtraFilesGroupBox'
ClientHeight = 27
ClientWidth = 413
DragCursor = 65524
Enabled = False
ParentColor = True
TabOrder = 2

View File

@ -9,41 +9,39 @@ LazarusResources.Add('TFindRenameIdentifierDialog','FORMDATA',[
+#4'Left'#3'#'#1#6'Height'#3#144#1#3'Top'#3#163#0#5'Width'#3#194#1#0#9'TGroup'
+'Box'#15'CurrentGroupBox'#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0#7'Ca'
+'ption'#6#15'CurrentGroupBox'#12'ClientHeight'#2'7'#11'ClientWidth'#3#176#1
+#10'DragCursor'#4#244#255#0#0#11'ParentColor'#9#8'TabOrder'#2#0#4'Left'#2#8#6
+'Height'#2'H'#3'Top'#2#8#5'Width'#3#180#1#0#8'TListBox'#14'CurrentListBox'#5
+'Align'#7#8'alClient'#16'ClickOnSelChange'#8#8'TabOrder'#2#0#8'TopIndex'#2
+#255#6'Height'#2'7'#5'Width'#3#176#1#0#0#0#9'TGroupBox'#11'NewGroupBox'#7'An'
+'chors'#11#5'akTop'#6'akLeft'#7'akRight'#0#7'Caption'#6#11'NewGroupBox'#12'C'
+'lientHeight'#2'$'#11'ClientWidth'#3#176#1#10'DragCursor'#4#244#255#0#0#11'P'
+'arentColor'#9#8'TabOrder'#2#1#4'Left'#2#8#6'Height'#2'5'#3'Top'#2'['#5'Widt'
+'h'#3#180#1#0#5'TEdit'#7'NewEdit'#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'
+#0#8'TabOrder'#2#0#4'Text'#6#7'NewEdit'#8'TabOrder'#2#0#4'Left'#2#6#6'Height'
+#2#23#3'Top'#2#6#5'Width'#3#4#1#0#0#9'TCheckBox'#14'RenameCheckBox'#11'Allow'
+'Grayed'#9#7'Anchors'#11#5'akTop'#7'akRight'#0#8'AutoSize'#9#7'Caption'#6#14
+'RenameCheckBox'#10'DragCursor'#4#244#255#0#0#8'OnChange'#7#20'RenameCheckBo'
+'xChange'#8'TabOrder'#2#1#11'UseOnChange'#9#4'Left'#3#18#1#6'Height'#2#23#3
+'Top'#2#6#5'Width'#3#151#0#0#0#0#9'TGroupBox'#13'ScopeGroupBox'#7'Anchors'#11
+#5'akTop'#6'akLeft'#7'akRight'#0#7'Caption'#6#13'ScopeGroupBox'#12'ClientHei'
+'ght'#3#187#0#11'ClientWidth'#3#177#1#10'DragCursor'#4#244#255#0#0#11'Parent'
+'Color'#9#8'TabOrder'#2#2#4'Left'#2#8#6'Height'#3#204#0#3'Top'#3#156#0#5'Wid'
+'th'#3#181#1#0#9'TCheckBox'#21'ScopeCommentsCheckBox'#11'AllowGrayed'#9#7'An'
+'chors'#11#5'akTop'#6'akLeft'#7'akRight'#0#8'AutoSize'#9#7'Caption'#6#21'Sco'
+'peCommentsCheckBox'#10'DragCursor'#4#244#255#0#0#8'TabOrder'#2#0#4'Left'#2#6
+#6'Height'#2#23#3'Top'#3#157#0#5'Width'#3#161#1#0#0#11'TRadioGroup'#15'Scope'
+'RadioGroup'#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0#7'Caption'#6#15'S'
+'copeRadioGroup'#7'Enabled'#8#13'Items.Strings'#1#6#15'In current Unit'#6#26
+'In current Project/Package'#6'!In all open projects and packages'#0#11'Pare'
+'ntColor'#9#4'Left'#2#6#6'Height'#2'X'#3'Top'#2#5#5'Width'#3#161#1#0#0#9'TGr'
+'oupBox'#18'ExtraFilesGroupBox'#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0
+#7'Caption'#6#18'ExtraFilesGroupBox'#12'ClientHeight'#2#27#11'ClientWidth'#3
+#157#1#10'DragCursor'#4#244#255#0#0#7'Enabled'#8#11'ParentColor'#9#8'TabOrde'
+'r'#2#2#4'Left'#2#6#6'Height'#2','#3'Top'#2'e'#5'Width'#3#161#1#0#5'TEdit'#14
+'ExtraFilesEdit'#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0#8'TabOrder'#2
+#0#4'Text'#6#14'ExtraFilesEdit'#8'TabOrder'#2#0#4'Left'#2#6#6'Height'#2#23#5
+'Width'#3#148#1#0#0#0#0#7'TButton'#18'FindOrRenameButton'#7'Anchors'#11#5'ak'
+'Top'#7'akRight'#0#7'Caption'#6#18'FindOrRenameButton'#7'OnClick'#7#23'FindO'
+'rRenameButtonClick'#8'TabOrder'#2#3#4'Left'#2'X'#6'Height'#2#25#3'Top'#3'p'
+#1#5'Width'#3#233#0#0#0#7'TButton'#12'CancelButton'#7'Anchors'#11#5'akTop'#7
+'akRight'#0#7'Caption'#6#12'CancelButton'#11'ModalResult'#2#2#8'TabOrder'#2#4
+#11'ParentColor'#9#8'TabOrder'#2#0#4'Left'#2#8#6'Height'#2'H'#3'Top'#2#8#5'W'
+'idth'#3#180#1#0#8'TListBox'#14'CurrentListBox'#5'Align'#7#8'alClient'#16'Cl'
+'ickOnSelChange'#8#8'TabOrder'#2#0#8'TopIndex'#2#255#6'Height'#2'7'#5'Width'
+#3#176#1#0#0#0#9'TGroupBox'#11'NewGroupBox'#7'Anchors'#11#5'akTop'#6'akLeft'
+#7'akRight'#0#7'Caption'#6#11'NewGroupBox'#12'ClientHeight'#2'$'#11'ClientWi'
+'dth'#3#176#1#11'ParentColor'#9#8'TabOrder'#2#1#4'Left'#2#8#6'Height'#2'5'#3
+'Top'#2'['#5'Width'#3#180#1#0#5'TEdit'#7'NewEdit'#7'Anchors'#11#5'akTop'#6'a'
+'kLeft'#7'akRight'#0#8'TabOrder'#2#0#4'Text'#6#7'NewEdit'#8'TabOrder'#2#0#4
+'Left'#2#6#6'Height'#2#23#3'Top'#2#6#5'Width'#3#4#1#0#0#9'TCheckBox'#14'Rena'
+'meCheckBox'#11'AllowGrayed'#9#7'Anchors'#11#5'akTop'#7'akRight'#0#8'AutoSiz'
+'e'#9#7'Caption'#6#14'RenameCheckBox'#8'OnChange'#7#20'RenameCheckBoxChange'
+#8'TabOrder'#2#1#11'UseOnChange'#9#4'Left'#3#18#1#6'Height'#2#23#3'Top'#2#6#5
+'Width'#3#151#0#0#0#0#9'TGroupBox'#13'ScopeGroupBox'#7'Anchors'#11#5'akTop'#6
+'akLeft'#7'akRight'#0#7'Caption'#6#13'ScopeGroupBox'#12'ClientHeight'#3#187#0
+#11'ClientWidth'#3#177#1#11'ParentColor'#9#8'TabOrder'#2#2#4'Left'#2#8#6'Hei'
+'ght'#3#204#0#3'Top'#3#156#0#5'Width'#3#181#1#0#9'TCheckBox'#21'ScopeComment'
+'sCheckBox'#11'AllowGrayed'#9#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0#8
+'AutoSize'#9#7'Caption'#6#21'ScopeCommentsCheckBox'#8'TabOrder'#2#0#4'Left'#2
+#6#6'Height'#2#23#3'Top'#3#157#0#5'Width'#3#161#1#0#0#11'TRadioGroup'#15'Sco'
+'peRadioGroup'#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0#7'Caption'#6#15
+'ScopeRadioGroup'#7'Enabled'#8#13'Items.Strings'#1#6#15'in current unit'#6#15
+'in main project'#6#30'in project/package owning file'#6'!in all open projec'
+'ts and packages'#0#11'ParentColor'#9#4'Left'#2#6#6'Height'#2'X'#3'Top'#2#5#5
+'Width'#3#161#1#0#0#9'TGroupBox'#18'ExtraFilesGroupBox'#7'Anchors'#11#5'akTo'
+'p'#6'akLeft'#7'akRight'#0#7'Caption'#6#18'ExtraFilesGroupBox'#12'ClientHeig'
+'ht'#2#27#11'ClientWidth'#3#157#1#7'Enabled'#8#11'ParentColor'#9#8'TabOrder'
+#2#2#4'Left'#2#6#6'Height'#2','#3'Top'#2'e'#5'Width'#3#161#1#0#5'TEdit'#14'E'
+'xtraFilesEdit'#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0#8'TabOrder'#2#0
+#4'Text'#6#14'ExtraFilesEdit'#8'TabOrder'#2#0#4'Left'#2#6#6'Height'#2#23#5'W'
+'idth'#3#148#1#0#0#0#0#7'TButton'#18'FindOrRenameButton'#7'Anchors'#11#5'akT'
+'op'#7'akRight'#0#7'Caption'#6#18'FindOrRenameButton'#7'OnClick'#7#23'FindOr'
+'RenameButtonClick'#8'TabOrder'#2#3#4'Left'#2'X'#6'Height'#2#25#3'Top'#3'p'#1
+#5'Width'#3#233#0#0#0#7'TButton'#12'CancelButton'#7'Anchors'#11#5'akTop'#7'a'
+'kRight'#0#7'Caption'#6#12'CancelButton'#11'ModalResult'#2#2#8'TabOrder'#2#4
+#4'Left'#3'P'#1#6'Height'#2#25#3'Top'#3'p'#1#5'Width'#2'Y'#0#0#0
]);

View File

@ -32,7 +32,7 @@ interface
uses
Classes, SysUtils, LCLProc, LResources, Forms, Controls, Graphics, Dialogs,
StdCtrls, Buttons, ExtCtrls,
CodeAtom, CodeCache, CodeToolManager,
AVL_Tree, CodeAtom, CodeCache, CodeToolManager,
LazarusIDEStrConsts, IDEProcs, IDEOptionDefs, MiscOptions, DialogProcs,
InputHistory, SearchResultView;
@ -64,6 +64,8 @@ type
public
procedure LoadFromConfig;
procedure SaveToConfig;
procedure LoadFromOptions(Options: TFindRenameIdentifierOptions);
procedure SaveToOptions(Options: TFindRenameIdentifierOptions);
procedure SetIdentifier(const NewIdentifierFilename: string;
const NewIdentifierPosition: TPoint);
property IdentifierFilename: string read FIdentifierFilename;
@ -73,17 +75,22 @@ type
function ShowFindRenameIdentifierDialog(const Filename: string;
const Position: TPoint; AllowRename: boolean): TModalResult;
const Position: TPoint; AllowRename: boolean;
Options: TFindRenameIdentifierOptions): TModalResult;
function GatherIdentifierReferences(Files: TStringList;
DeclarationCode: TCodeBuffer; const DeclarationCaretXY: TPoint;
SearchInComments: boolean): TModalResult;
procedure ShowReferences(DeclarationCode: TCodeBuffer;
const DeclarationCaretXY: TPoint; TargetCode: TCodeBuffer;
ListOfPCodeXYPosition: TList);
TreeOfPCodeXYPosition: TAVLTree; ClearItems: boolean; SearchPageIndex: integer);
implementation
function ShowFindRenameIdentifierDialog(const Filename: string;
const Position: TPoint; AllowRename: boolean): TModalResult;
const Position: TPoint; AllowRename: boolean;
Options: TFindRenameIdentifierOptions): TModalResult;
var
FindRenameIdentifierDialog: TFindRenameIdentifierDialog;
begin
@ -93,49 +100,138 @@ begin
FindRenameIdentifierDialog.SetIdentifier(Filename,Position);
FindRenameIdentifierDialog.AllowRename:=AllowRename;
Result:=FindRenameIdentifierDialog.ShowModal;
if Result=mrOk then
if Options<>nil then
FindRenameIdentifierDialog.SaveToOptions(Options);
finally
FindRenameIdentifierDialog.Free;
end;
end;
function GatherIdentifierReferences(Files: TStringList;
DeclarationCode: TCodeBuffer; const DeclarationCaretXY: TPoint;
SearchInComments: boolean): TModalResult;
var
i: Integer;
SearchPageIndex: LongInt;
LoadResult: TModalResult;
Code: TCodeBuffer;
ListOfPCodeXYPosition: TList;
TreeOfPCodeXYPosition: TAVLTree;
Identifier: string;
OldSearchPageIndex: LongInt;
begin
Result:=mrCancel;
ListOfPCodeXYPosition:=nil;
TreeOfPCodeXYPosition:=nil;
SearchPageIndex:=-1;
try
// sort files
Files.Sort;
// remove doubles
i:=0;
while i<=Files.Count-2 do begin
while (i<=Files.Count-2) and (CompareFilenames(Files[i],Files[i+1])=0) do
begin
Files.Delete(i+1);
end;
inc(i);
end;
// create a search result page
CodeToolBoss.GetIdentifierAt(DeclarationCode,
DeclarationCaretXY.X,DeclarationCaretXY.Y,Identifier);
// search in every file
for i:=0 to Files.Count-1 do begin
LoadResult:=
LoadCodeBuffer(Code,Files[i],[lbfCheckIfText,lbfUpdateFromDisk]);
if LoadResult=mrAbort then exit;
if LoadResult<>mrOk then continue;
// create search page
if SearchPageIndex<0 then begin
SearchPageIndex:=SearchResultsView.AddResult(
'References of '+Identifier,
Identifier,
ExtractFilePath(Code.Filename),
'*.pas;*.pp;*.inc',
[fifWholeWord,fifSearchDirectories]);
if SearchPageIndex<0 then exit;
SearchResultsView.BeginUpdate(SearchPageIndex);
end;
// search references
CodeToolBoss.FreeListOfPCodeXYPosition(ListOfPCodeXYPosition);
if not CodeToolBoss.FindReferences(
DeclarationCode,DeclarationCaretXY.X,DeclarationCaretXY.Y,
Code, not SearchInComments, ListOfPCodeXYPosition) then
begin
Result:=mrAbort;
exit;
end;
// add to tree
if ListOfPCodeXYPosition<>nil then begin
if TreeOfPCodeXYPosition=nil then
TreeOfPCodeXYPosition:=CodeToolBoss.CreateTreeOfPCodeXYPosition;
CodeToolBoss.AddListToTreeOfPCodeXYPosition(ListOfPCodeXYPosition,
TreeOfPCodeXYPosition,true,false);
end;
end;
// show result
ShowReferences(DeclarationCode,DeclarationCaretXY,
Code,TreeOfPCodeXYPosition,false,SearchPageIndex);
OldSearchPageIndex:=SearchPageIndex;
SearchPageIndex:=-1;
SearchResultsView.EndUpdate(OldSearchPageIndex);
SearchResultsView.ShowOnTop;
finally
if SearchPageIndex>=0 then
SearchResultsView.EndUpdate(SearchPageIndex);
CodeToolBoss.FreeListOfPCodeXYPosition(ListOfPCodeXYPosition);
CodeToolBoss.FreeTreeOfPCodeXYPosition(TreeOfPCodeXYPosition);
end;
Result:=mrOk;
end;
procedure ShowReferences(DeclarationCode: TCodeBuffer;
const DeclarationCaretXY: TPoint; TargetCode: TCodeBuffer;
ListOfPCodeXYPosition: TList);
TreeOfPCodeXYPosition: TAVLTree; ClearItems: boolean;
SearchPageIndex: integer);
var
Identifier: string;
SearchPageIndex: LongInt;
i: Integer;
CodePos: PCodeXYPosition;
CurLine: String;
TrimmedLine: String;
TrimCnt: Integer;
ANode: TAVLTreeNode;
begin
CodeToolBoss.GetIdentifierAt(DeclarationCode,
DeclarationCaretXY.X,DeclarationCaretXY.Y,Identifier);
SearchPageIndex:=SearchResultsView.AddResult(
'References of '+Identifier,
Identifier,
ExtractFilePath(TargetCode.Filename),
'*.pas;*.pp;*.inc',
[fifWholeWord,fifSearchDirectories]);
SearchResultsView.BeginUpdate(SearchPageIndex);
SearchResultsView.Items[SearchPageIndex].Clear;
if (ListOfPCodeXYPosition<>nil) then
for i:=0 to ListOfPCodeXYPosition.Count-1 do begin
CodePos:=PCodeXYPosition(ListOfPCodeXYPosition[i]);
if ClearItems then
SearchResultsView.Items[SearchPageIndex].Clear;
if (TreeOfPCodeXYPosition<>nil) then begin
ANode:=TreeOfPCodeXYPosition.FindLowest;
while ANode<>nil do begin
CodePos:=PCodeXYPosition(ANode.Data);
CurLine:=TrimRight(CodePos^.Code.GetLine(CodePos^.Y-1));
TrimmedLine:=Trim(CurLine);
TrimCnt:=length(CurLine)-length(TrimmedLine);
//debugln('ShowReferences x=',dbgs(CodePos^.x),' y=',dbgs(CodePos^.y),' ',CurLine);
SearchResultsView.AddMatch(SearchPageIndex,
TargetCode.Filename,
CodePos^.Code.Filename,
Point(CodePos^.X,CodePos^.Y),
TrimmedLine,
CodePos^.X-TrimCnt, length(Identifier));
ANode:=TreeOfPCodeXYPosition.FindSuccessor(ANode);
end;
end;
SearchResultsView.EndUpdate(SearchPageIndex);
SearchResultsView.ShowOnTop;
end;
{ TFindRenameIdentifierDialog }
@ -156,7 +252,11 @@ begin
ScopeCommentsCheckBox.Caption:='Search in comments too';
ScopeGroupBox.Caption:='Search where';
ScopeRadioGroup.Caption:='Scope';
ScopeRadioGroup.Items[0]:='in current unit';
ScopeRadioGroup.Items[1]:='in main project';
ScopeRadioGroup.Items[2]:='in project/package owning current unit';
ScopeRadioGroup.Items[3]:='in all open packages and projects';
LoadFromConfig;
end;
@ -203,29 +303,37 @@ begin
end;
procedure TFindRenameIdentifierDialog.LoadFromConfig;
var
Options: TFindRenameIdentifierOptions;
begin
Options:=MiscellaneousOptions.FindRenameIdentifierOptions;
LoadFromOptions(MiscellaneousOptions.FindRenameIdentifierOptions);
end;
procedure TFindRenameIdentifierDialog.SaveToConfig;
begin
SaveToOptions(MiscellaneousOptions.FindRenameIdentifierOptions);
end;
procedure TFindRenameIdentifierDialog.LoadFromOptions(
Options: TFindRenameIdentifierOptions);
begin
RenameCheckBox.Checked:=Options.Rename;
ExtraFilesEdit.Text:=StringListToText(Options.ExtraFiles,';',true);
NewEdit.Text:=Options.RenameTo;
ScopeCommentsCheckBox.Checked:=Options.SearchInComments;
case Options.Scope of
frCurrentUnit: ScopeRadioGroup.ItemIndex:=0;
frCurrentProjectPackage: ScopeRadioGroup.ItemIndex:=1;
frProject: ScopeRadioGroup.ItemIndex:=1;
frOwnerProjectPackage: ScopeRadioGroup.ItemIndex:=2;
else
ScopeRadioGroup.ItemIndex:=2;
ScopeRadioGroup.ItemIndex:=3;
end;
UpdateRename;
end;
procedure TFindRenameIdentifierDialog.SaveToConfig;
procedure TFindRenameIdentifierDialog.SaveToOptions(
Options: TFindRenameIdentifierOptions);
var
Options: TFindRenameIdentifierOptions;
ExtraFileList: TStringList;
begin
Options:=MiscellaneousOptions.FindRenameIdentifierOptions;
Options.Rename:=RenameCheckBox.Checked;
ExtraFileList:=SplitString(ExtraFilesEdit.Text,';');
Options.ExtraFiles.Assign(ExtraFileList);
@ -234,7 +342,8 @@ begin
Options.SearchInComments:=ScopeCommentsCheckBox.Checked;
case ScopeRadioGroup.ItemIndex of
0: Options.Scope:=frCurrentUnit;
1: Options.Scope:=frCurrentProjectPackage;
1: Options.Scope:=frProject;
2: Options.Scope:=frOwnerProjectPackage;
else Options.Scope:=frAllOpenProjectsAndPackages;
end;
end;

View File

@ -63,7 +63,8 @@ uses
Forms, Buttons, Menus, FileCtrl, Controls, GraphType, Graphics, ExtCtrls,
Dialogs,
// codetools
Laz_XMLCfg, CodeToolsStructs, CodeToolManager, CodeCache, DefineTemplates,
AVL_Tree, Laz_XMLCfg, CodeToolsStructs, CodeToolManager, CodeCache,
DefineTemplates,
// IDE interface
AllIDEIntf, ObjectInspector, PropEdits, IDECommands, SrcEditorIntf,
// synedit
@ -9250,54 +9251,79 @@ end;
-------------------------------------------------------------------------------}
procedure TMainIDE.DoFindIdentifierReferences;
var
ActiveSrcEdit, DeclarationSrcEdit: TSourceEditor;
ActiveUnitInfo, DeclarationUnitInfo: TUnitInfo;
TargetSrcEdit, DeclarationSrcEdit: TSourceEditor;
TargetUnitInfo, DeclarationUnitInfo: TUnitInfo;
NewSource: TCodeBuffer;
NewX, NewY, NewTopLine: integer;
LogCaretXY, DeclarationCaretXY: TPoint;
ListOfPCodeXYPosition: TList;
Options: TFindRenameIdentifierOptions;
OwnerList: TList;
ExtraFiles: TStrings;
Files: TStringList;
begin
if not BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,[]) then exit;
if not BeginCodeTool(TargetSrcEdit,TargetUnitInfo,[]) then exit;
// find the main declaration
LogCaretXY:=ActiveSrcEdit.EditorComponent.LogicalCaretXY;
if not CodeToolBoss.FindMainDeclaration(ActiveUnitInfo.Source,
LogCaretXY:=TargetSrcEdit.EditorComponent.LogicalCaretXY;
if not CodeToolBoss.FindMainDeclaration(TargetUnitInfo.Source,
LogCaretXY.X,LogCaretXY.Y,
NewSource,NewX,NewY,NewTopLine) then
begin
DoJumpToCodeToolBossError;
exit;
end;
DoJumpToCodePos(ActiveSrcEdit, ActiveUnitInfo,
DoJumpToCodePos(TargetSrcEdit, TargetUnitInfo,
NewSource, NewX, NewY, NewTopLine, true);
GetCurrentUnit(DeclarationSrcEdit,DeclarationUnitInfo);
DeclarationCaretXY:=DeclarationSrcEdit.EditorComponent.LogicalCaretXY;
debugln('TMainIDE.DoFindIdentifierReferences A DeclarationCaretXY=x=',dbgs(DeclarationCaretXY.X),' y=',dbgs(DeclarationCaretXY.Y));
// let user choose the search scope
if ShowFindRenameIdentifierDialog(DeclarationUnitInfo.Source.Filename,
LogCaretXY,false)<>mrOk
DeclarationCaretXY,false,nil)<>mrOk
then exit;
ListOfPCodeXYPosition:=nil;
Files:=nil;
OwnerList:=nil;
try
// search
if not CodeToolBoss.FindReferences(
DeclarationUnitInfo.Source,DeclarationCaretXY.X,DeclarationCaretXY.Y,
ActiveUnitInfo.Source,
not MiscellaneousOptions.FindRenameIdentifierOptions.SearchInComments,
ListOfPCodeXYPosition) then
begin
DoJumpToCodeToolBossError;
exit;
// create the file list
Files:=TStringList.Create;
Files.Add(TargetUnitInfo.Filename);
Options:=MiscellaneousOptions.FindRenameIdentifierOptions;
case Options.Scope of
frProject,frOwnerProjectPackage,frAllOpenProjectsAndPackages:
begin
if Options.Scope=frProject then begin
OwnerList:=TList.Create;
OwnerList.Add(Project1);
end else begin
OwnerList:=PkgBoss.GetOwnersOfUnit(TargetUnitInfo.Filename);
if Options.Scope=frAllOpenProjectsAndPackages then begin
// TODO
end;
end;
ExtraFiles:=PkgBoss.GetSourceFilesOfOwners(OwnerList);
try
if ExtraFiles<>nil then
Files.AddStrings(ExtraFiles);
finally
ExtraFiles.Free;
end;
end;
end;
// show result
CreateSearchResultWindow;
ShowReferences(DeclarationUnitInfo.Source,DeclarationCaretXY,
ActiveUnitInfo.Source,ListOfPCodeXYPosition);
GatherIdentifierReferences(Files,DeclarationUnitInfo.Source,
DeclarationCaretXY,Options.SearchInComments);
if CodeToolBoss.ErrorMessage<>'' then
DoJumpToCodeToolBossError;
finally
CodeToolBoss.FreeListOfPCodeXYPosition(ListOfPCodeXYPosition);
Files.Free;
OwnerList.Free;
end;
end;
@ -10782,6 +10808,9 @@ end.
{ =============================================================================
$Log$
Revision 1.774 2004/09/20 20:22:11 mattias
implemented Refactoring Tool: Find Identfier References
Revision 1.773 2004/09/18 01:02:23 mattias
started new feature: find identifier references

View File

@ -38,7 +38,8 @@ type
TFindRenameScope = (
frCurrentUnit,
frCurrentProjectPackage, // the project/package the current unit beongs to
frOwnerProjectPackage, // the project/package the current unit beongs to
frProject,
frAllOpenProjectsAndPackages
);
@ -97,7 +98,8 @@ const
ResourcestringInsertPolicyNames: array[TResourcestringInsertPolicy] of string
= ('None', 'Append', 'Alphabetically', 'Context');
FindRenameScopeNames: array[TFindRenameScope] of string = (
'CurrentUnit', 'CurrentProjectPackage', 'AllOpenProjectsAndPackages'
'CurrentUnit', 'Project', 'OwnerProjectPackage',
'AllOpenProjectsAndPackages'
);
var MiscellaneousOptions: TMiscellaneousOptions;

View File

@ -121,7 +121,7 @@ type
WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
private
function PageExists(const APageName: string): boolean;
function GetPageIndex(APageName: string): integer;
function GetPageIndex(const APageName: string): integer;
function GetListBox(APageIndex: integer): TLazSearchResultLB;
procedure ListBoxClicked(Sender: TObject);
procedure ListBoxDoubleClicked(Sender: TObject);
@ -277,10 +277,12 @@ begin
if Assigned(CurrentLB) then
begin
CurrentLB.EndUpdate;
CurrentLB.ItemIndex:= 0;
CurrentLB.TopIndex:= 0;
end;//if
end;//EndUpdate
if CurrentLB.Items.Count>0 then begin
CurrentLB.ItemIndex:= 0;
CurrentLB.TopIndex:= 0;
end;
end;
end;
{Brings the results tab named APageName to front.
If APageName does not exist, does nothing}
@ -607,7 +609,7 @@ begin
end;//if
end;
function TSearchResultsView.GetPageIndex(APageName: string): integer;
function TSearchResultsView.GetPageIndex(const APageName: string): integer;
var
i: integer;
begin

View File

@ -45,6 +45,8 @@ type
public
function AddUnitDependenciesForComponentClasses(const UnitFilename: string;
ComponentClassnames: TStrings): TModalResult; virtual; abstract;
function GetOwnersOfUnit(const UnitFilename: string): TList; virtual; abstract;
function GetSourceFilesOfOwners(OwnerList: TList): TStrings; virtual; abstract;
end;
var

View File

@ -125,7 +125,8 @@ end;
{-------------------------------------------------------------------------------
Procedure DragInitControl(Control : TControl; Immediate : Boolean;
Threshold: Integer);
Initializes the dragging. If Immediate=True it starts the dragging, otherwise
it will be started when the user moves the mouse more than DragThreshold
pixel.
@ -361,6 +362,9 @@ end;
{ =============================================================================
$Log$
Revision 1.6 2004/09/20 20:22:12 mattias
implemented Refactoring Tool: Find Identfier References
Revision 1.5 2004/06/01 09:58:35 mattias
implemented setting TCustomPage.PageIndex from Andrew Haines

View File

@ -181,8 +181,9 @@ type
function GetMissingDependenciesForUnit(const UnitFilename: string;
ComponentClassnames: TStrings;
var List: TObjectArray): TModalResult;
function GetOwnersOfUnit(const UnitFilename: string): TList;
function GetOwnersOfUnit(const UnitFilename: string): TList; override;
function GetSourceFilesOfOwners(OwnerList: TList): TStrings; override;
// package graph
function AddPackageToGraph(APackage: TLazPackage; Replace: boolean): TModalResult;
function DoShowPackageGraph: TModalResult;
@ -2794,6 +2795,46 @@ begin
FreeThenNil(Result);
end;
function TPkgManager.GetSourceFilesOfOwners(OwnerList: TList): TStrings;
procedure AddFile(TheOwner: TObject; const Filename: string);
begin
if Result=nil then Result:=TStringList.Create;
Result.AddObject(Filename,TheOwner);
end;
var
CurOwner: TObject;
CurPackage: TLazPackage;
CurPkgFile: TPkgFile;
CurProject: TProject;
CurUnit: TUnitInfo;
i: Integer;
j: Integer;
begin
Result:=nil;
if OwnerList=nil then exit;
for i:=0 to OwnerList.Count-1 do begin
CurOwner:=TObject(OwnerList[i]);
if CurOwner is TLazPackage then begin
CurPackage:=TLazPackage(CurOwner);
for j:=0 to CurPackage.FileCount-1 do begin
CurPkgFile:=CurPackage.Files[j];
if CurPkgFile.FileType in PkgFileUnitTypes then
AddFile(CurOwner,CurPkgFile.Filename);
end;
end else if CurOwner is TProject then begin
CurProject:=TProject(CurOwner);
CurUnit:=CurProject.FirstPartOfProject;
while CurUnit<>nil do begin
if FilenameIsPascalSource(CurUnit.Filename) then
AddFile(CurOwner,CurUnit.Filename);
CurUnit:=CurUnit.NextPartOfProject;
end;
end;
end;
end;
function TPkgManager.DoAddActiveUnitToAPackage: TModalResult;
var
ActiveSourceEditor: TSourceEditor;