mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-06-03 19:38:16 +02:00
codetools: FindUsedUnitReferences
git-svn-id: trunk@42681 -
This commit is contained in:
parent
ae2989ecac
commit
5364c52f95
3
.gitattributes
vendored
3
.gitattributes
vendored
@ -740,6 +740,8 @@ components/codetools/examples/finddeclaration.lpi svneol=native#text/plain
|
|||||||
components/codetools/examples/finddeclaration.lpr svneol=native#text/plain
|
components/codetools/examples/finddeclaration.lpr svneol=native#text/plain
|
||||||
components/codetools/examples/findunusedunits.lpi svneol=native#text/plain
|
components/codetools/examples/findunusedunits.lpi svneol=native#text/plain
|
||||||
components/codetools/examples/findunusedunits.lpr svneol=native#text/pascal
|
components/codetools/examples/findunusedunits.lpr svneol=native#text/pascal
|
||||||
|
components/codetools/examples/findusedunitreferences.lpi svneol=native#text/plain
|
||||||
|
components/codetools/examples/findusedunitreferences.lpr svneol=native#text/plain
|
||||||
components/codetools/examples/fixdefinitionorder.lpi svneol=native#text/plain
|
components/codetools/examples/fixdefinitionorder.lpi svneol=native#text/plain
|
||||||
components/codetools/examples/fixdefinitionorder.lpr svneol=native#text/plain
|
components/codetools/examples/fixdefinitionorder.lpr svneol=native#text/plain
|
||||||
components/codetools/examples/fixfilenames.lpi svneol=native#text/plain
|
components/codetools/examples/fixfilenames.lpi svneol=native#text/plain
|
||||||
@ -812,6 +814,7 @@ components/codetools/examples/scanexamples/test.h svneol=native#text/plain
|
|||||||
components/codetools/examples/scanexamples/tgeneric2.pas svneol=native#text/plain
|
components/codetools/examples/scanexamples/tgeneric2.pas svneol=native#text/plain
|
||||||
components/codetools/examples/scanexamples/uglyifdefs.pas svneol=native#text/plain
|
components/codetools/examples/scanexamples/uglyifdefs.pas svneol=native#text/plain
|
||||||
components/codetools/examples/scanexamples/unusedunits1.pas svneol=native#text/pascal
|
components/codetools/examples/scanexamples/unusedunits1.pas svneol=native#text/pascal
|
||||||
|
components/codetools/examples/scanexamples/usedunitrefs1.pas svneol=native#text/plain
|
||||||
components/codetools/examples/scanexamples/wrongforwarddefinitions.pas svneol=native#text/plain
|
components/codetools/examples/scanexamples/wrongforwarddefinitions.pas svneol=native#text/plain
|
||||||
components/codetools/examples/setincludepath.lpi svneol=native#text/plain
|
components/codetools/examples/setincludepath.lpi svneol=native#text/plain
|
||||||
components/codetools/examples/setincludepath.pas svneol=native#text/plain
|
components/codetools/examples/setincludepath.pas svneol=native#text/plain
|
||||||
|
@ -474,7 +474,7 @@ type
|
|||||||
function GatherOverloads(Code: TCodeBuffer; X,Y: integer;
|
function GatherOverloads(Code: TCodeBuffer; X,Y: integer;
|
||||||
out Graph: TDeclarationOverloadsGraph): boolean;
|
out Graph: TDeclarationOverloadsGraph): boolean;
|
||||||
|
|
||||||
// rename, remove identifier
|
// find references, rename identifier, remove identifier
|
||||||
function FindReferences(IdentifierCode: TCodeBuffer;
|
function FindReferences(IdentifierCode: TCodeBuffer;
|
||||||
X, Y: integer; SearchInCode: TCodeBuffer; SkipComments: boolean;
|
X, Y: integer; SearchInCode: TCodeBuffer; SkipComments: boolean;
|
||||||
var ListOfPCodeXYPosition: TFPList;
|
var ListOfPCodeXYPosition: TFPList;
|
||||||
@ -482,6 +482,8 @@ type
|
|||||||
): boolean;
|
): boolean;
|
||||||
function FindUnitReferences(UnitCode, TargetCode: TCodeBuffer;
|
function FindUnitReferences(UnitCode, TargetCode: TCodeBuffer;
|
||||||
SkipComments: boolean; var ListOfPCodeXYPosition: TFPList): boolean;
|
SkipComments: boolean; var ListOfPCodeXYPosition: TFPList): boolean;
|
||||||
|
function FindUsedUnitReferences(Code: TCodeBuffer; X, Y: integer;
|
||||||
|
SkipComments: boolean; var ListOfPCodeXYPosition: TFPList): boolean;
|
||||||
function RenameIdentifier(TreeOfPCodeXYPosition: TAVLTree;
|
function RenameIdentifier(TreeOfPCodeXYPosition: TAVLTree;
|
||||||
const OldIdentifier, NewIdentifier: string;
|
const OldIdentifier, NewIdentifier: string;
|
||||||
DeclarationCode: TCodeBuffer = nil; DeclarationCaretXY: PPoint = nil): boolean;
|
DeclarationCode: TCodeBuffer = nil; DeclarationCaretXY: PPoint = nil): boolean;
|
||||||
@ -2530,6 +2532,7 @@ end;
|
|||||||
|
|
||||||
function TCodeToolManager.FindUnitReferences(UnitCode, TargetCode: TCodeBuffer;
|
function TCodeToolManager.FindUnitReferences(UnitCode, TargetCode: TCodeBuffer;
|
||||||
SkipComments: boolean; var ListOfPCodeXYPosition: TFPList): boolean;
|
SkipComments: boolean; var ListOfPCodeXYPosition: TFPList): boolean;
|
||||||
|
// finds unit name of UnitCode in unit of TargetCode
|
||||||
begin
|
begin
|
||||||
Result:=false;
|
Result:=false;
|
||||||
{$IFDEF CTDEBUG}
|
{$IFDEF CTDEBUG}
|
||||||
@ -2548,6 +2551,34 @@ begin
|
|||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TCodeToolManager.FindUsedUnitReferences(Code: TCodeBuffer; X,
|
||||||
|
Y: integer; SkipComments: boolean; var ListOfPCodeXYPosition: TFPList
|
||||||
|
): boolean;
|
||||||
|
// finds in unit of Code all references of the unit at the uses clause at X,Y
|
||||||
|
var
|
||||||
|
CursorPos: TCodeXYPosition;
|
||||||
|
begin
|
||||||
|
Result:=false;
|
||||||
|
{$IFDEF CTDEBUG}
|
||||||
|
DebugLn('TCodeToolManager.FindUsedUnitReferences A ',Code.Filename,' X=',X,' Y=',Y,' SkipComments=',SkipComments);
|
||||||
|
{$ENDIF}
|
||||||
|
ListOfPCodeXYPosition:=nil;
|
||||||
|
if not InitCurCodeTool(Code) then exit;
|
||||||
|
CursorPos.X:=X;
|
||||||
|
CursorPos.Y:=Y;
|
||||||
|
CursorPos.Code:=Code;
|
||||||
|
try
|
||||||
|
FCurCodeTool.FindUsedUnitReferences(CursorPos,SkipComments,
|
||||||
|
ListOfPCodeXYPosition);
|
||||||
|
Result:=true;
|
||||||
|
except
|
||||||
|
on e: Exception do HandleException(e);
|
||||||
|
end;
|
||||||
|
{$IFDEF CTDEBUG}
|
||||||
|
DebugLn('TCodeToolManager.FindUnitReferences END ');
|
||||||
|
{$ENDIF}
|
||||||
|
end;
|
||||||
|
|
||||||
function TCodeToolManager.RenameIdentifier(TreeOfPCodeXYPosition: TAVLTree;
|
function TCodeToolManager.RenameIdentifier(TreeOfPCodeXYPosition: TAVLTree;
|
||||||
const OldIdentifier, NewIdentifier: string; DeclarationCode: TCodeBuffer;
|
const OldIdentifier, NewIdentifier: string; DeclarationCode: TCodeBuffer;
|
||||||
DeclarationCaretXY: PPoint): boolean;
|
DeclarationCaretXY: PPoint): boolean;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<fpdoc-descriptions>
|
<fpdoc-descriptions>
|
||||||
<package name="CodeTools">
|
<package name="CodeTools">
|
||||||
<module name="CodeToolManager">
|
<module name="CodeToolManager">
|
||||||
@ -6,6 +6,8 @@
|
|||||||
<short>Returns the unit search path of the given directory separated by semicolon</short>
|
<short>Returns the unit search path of the given directory separated by semicolon</short>
|
||||||
<descr>The unit path is created from the define templates variable #UnitPath.</descr>
|
<descr>The unit path is created from the define templates variable #UnitPath.</descr>
|
||||||
</element>
|
</element>
|
||||||
|
<element name="TCodeToolManager.FindUnitReferences"><short>Searches unitname of UnitCode in unit of TargetCode</short>
|
||||||
|
</element>
|
||||||
</module>
|
</module>
|
||||||
</package>
|
</package>
|
||||||
</fpdoc-descriptions>
|
</fpdoc-descriptions>
|
||||||
|
64
components/codetools/examples/findusedunitreferences.lpi
Normal file
64
components/codetools/examples/findusedunitreferences.lpi
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<CONFIG>
|
||||||
|
<ProjectOptions>
|
||||||
|
<Version Value="9"/>
|
||||||
|
<General>
|
||||||
|
<Flags>
|
||||||
|
<LRSInOutputDirectory Value="False"/>
|
||||||
|
</Flags>
|
||||||
|
<SessionStorage Value="InProjectDir"/>
|
||||||
|
<MainUnit Value="0"/>
|
||||||
|
<Title Value="findusedunitreferences"/>
|
||||||
|
</General>
|
||||||
|
<BuildModes Count="1">
|
||||||
|
<Item1 Name="default" Default="True"/>
|
||||||
|
</BuildModes>
|
||||||
|
<PublishOptions>
|
||||||
|
<Version Value="2"/>
|
||||||
|
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
|
||||||
|
<ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
|
||||||
|
</PublishOptions>
|
||||||
|
<RunParams>
|
||||||
|
<local>
|
||||||
|
<FormatVersion Value="1"/>
|
||||||
|
<LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
|
||||||
|
</local>
|
||||||
|
</RunParams>
|
||||||
|
<RequiredPackages Count="1">
|
||||||
|
<Item1>
|
||||||
|
<PackageName Value="CodeTools"/>
|
||||||
|
</Item1>
|
||||||
|
</RequiredPackages>
|
||||||
|
<Units Count="4">
|
||||||
|
<Unit0>
|
||||||
|
<Filename Value="findusedunitreferences.lpr"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
<UnitName Value="findusedunitreferences"/>
|
||||||
|
</Unit0>
|
||||||
|
<Unit1>
|
||||||
|
<Filename Value="scanexamples/simpleunit1.pas"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
<UnitName Value="SimpleUnit1"/>
|
||||||
|
</Unit1>
|
||||||
|
<Unit2>
|
||||||
|
<Filename Value="scanexamples/unusedunits1.pas"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
<UnitName Value="UnusedUnits1"/>
|
||||||
|
</Unit2>
|
||||||
|
<Unit3>
|
||||||
|
<Filename Value="scanexamples/usedunitrefs1.pas"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
<UnitName Value="UsedUnitRefs1"/>
|
||||||
|
</Unit3>
|
||||||
|
</Units>
|
||||||
|
</ProjectOptions>
|
||||||
|
<CompilerOptions>
|
||||||
|
<Version Value="11"/>
|
||||||
|
<SearchPaths>
|
||||||
|
<OtherUnitFiles Value="scanexamples"/>
|
||||||
|
</SearchPaths>
|
||||||
|
<Other>
|
||||||
|
<CompilerPath Value="$(CompPath)"/>
|
||||||
|
</Other>
|
||||||
|
</CompilerOptions>
|
||||||
|
</CONFIG>
|
91
components/codetools/examples/findusedunitreferences.lpr
Normal file
91
components/codetools/examples/findusedunitreferences.lpr
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
{
|
||||||
|
***************************************************************************
|
||||||
|
* *
|
||||||
|
* 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:
|
||||||
|
Simple demonstrating, how to setup the codetools, FPC and Lazarus Source
|
||||||
|
directory to find what unit A uses of unit B.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
findusedunitreferences filename line column
|
||||||
|
|
||||||
|
Filename is a unit.
|
||||||
|
Line, column is a unit within a uses section.
|
||||||
|
}
|
||||||
|
program FindUsedUnitReferences;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, CodeCache, CodeToolManager, DefineTemplates,
|
||||||
|
CodeToolsConfig, FileProcs, usedunitrefs1;
|
||||||
|
|
||||||
|
const
|
||||||
|
ConfigFilename = 'codetools.config';
|
||||||
|
var
|
||||||
|
Code: TCodeBuffer;
|
||||||
|
Filename: String;
|
||||||
|
ListOfPCodeXYPosition: TFPList;
|
||||||
|
X: Integer;
|
||||||
|
Y: Integer;
|
||||||
|
begin
|
||||||
|
if (ParamCount>=1) and (Paramcount<3) then begin
|
||||||
|
writeln('Usage:');
|
||||||
|
writeln(' ',ParamStr(0));
|
||||||
|
writeln(' ',ParamStr(0),' <filename> <X> <Y>');
|
||||||
|
Halt(1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
CodeToolBoss.SimpleInit(ConfigFilename);
|
||||||
|
|
||||||
|
// Example: find all references to unit Math
|
||||||
|
Filename:=ExpandFileName('scanexamples/usedunitrefs1.pas');
|
||||||
|
X:=23;
|
||||||
|
Y:=8;
|
||||||
|
|
||||||
|
if (ParamCount>=3) then begin
|
||||||
|
Filename:=CleanAndExpandFilename(ParamStr(1));
|
||||||
|
X:=StrToInt(ParamStr(2));
|
||||||
|
Y:=StrToInt(ParamStr(3));
|
||||||
|
writeln('File: ',Filename,' Line=',Y,' Column=',X);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Step 1: load the file
|
||||||
|
Code:=CodeToolBoss.LoadFile(Filename,false,false);
|
||||||
|
if Code=nil then
|
||||||
|
raise Exception.Create('loading failed '+Filename);
|
||||||
|
|
||||||
|
// Step 2: find references
|
||||||
|
writeln('Filename: ',Code.Filename);
|
||||||
|
ListOfPCodeXYPosition:=nil;
|
||||||
|
try
|
||||||
|
if CodeToolBoss.FindUsedUnitReferences(Code,X,Y,false,ListOfPCodeXYPosition) then
|
||||||
|
begin
|
||||||
|
writeln('List:');
|
||||||
|
writeln(ListOfPCodeXYPositionToStr(ListOfPCodeXYPosition));
|
||||||
|
end else begin
|
||||||
|
writeln('CodeToolBoss.FindUsedUnitReferences failed: ',CodeToolBoss.ErrorMessage);
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
FreeListOfPCodeXYPosition(ListOfPCodeXYPosition);
|
||||||
|
end;
|
||||||
|
end.
|
||||||
|
|
28
components/codetools/examples/scanexamples/usedunitrefs1.pas
Normal file
28
components/codetools/examples/scanexamples/usedunitrefs1.pas
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
unit UsedUnitRefs1;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, math, process;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
procedure DoSome;
|
||||||
|
var
|
||||||
|
c: TComponent;
|
||||||
|
d: float;
|
||||||
|
i: Int64;
|
||||||
|
begin
|
||||||
|
c:=TComponent.Create(nil);
|
||||||
|
c.Free;
|
||||||
|
d:=1.3;
|
||||||
|
i:=round(d);
|
||||||
|
writeln(i+abs(d));
|
||||||
|
writeln(sin(d));
|
||||||
|
writeln(MinFloat<d);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
@ -727,6 +727,9 @@ type
|
|||||||
function CheckParameterSyntax(StartPos, CleanCursorPos: integer;
|
function CheckParameterSyntax(StartPos, CleanCursorPos: integer;
|
||||||
out ParameterAtom, ProcNameAtom: TAtomPosition;
|
out ParameterAtom, ProcNameAtom: TAtomPosition;
|
||||||
out ParameterIndex: integer): boolean;
|
out ParameterIndex: integer): boolean;
|
||||||
|
procedure OnFindUsedUnitIdentifier(Sender: TPascalParserTool;
|
||||||
|
IdentifierCleanPos: integer; Range: TEPRIRange;
|
||||||
|
Node: TCodeTreeNode; Data: Pointer; var Abort: boolean);
|
||||||
protected
|
protected
|
||||||
public
|
public
|
||||||
constructor Create;
|
constructor Create;
|
||||||
@ -823,7 +826,11 @@ type
|
|||||||
function FindReferences(const CursorPos: TCodeXYPosition;
|
function FindReferences(const CursorPos: TCodeXYPosition;
|
||||||
SkipComments: boolean; out ListOfPCodeXYPosition: TFPList): boolean;
|
SkipComments: boolean; out ListOfPCodeXYPosition: TFPList): boolean;
|
||||||
function FindUnitReferences(UnitCode: TCodeBuffer;
|
function FindUnitReferences(UnitCode: TCodeBuffer;
|
||||||
SkipComments: boolean; out ListOfPCodeXYPosition: TFPList): boolean;
|
SkipComments: boolean; out ListOfPCodeXYPosition: TFPList): boolean; // searches unitname of UnitCode
|
||||||
|
procedure FindUsedUnitReferences(const CursorPos: TCodeXYPosition;
|
||||||
|
SkipComments: boolean; out ListOfPCodeXYPosition: TFPList); // searches all references of unit in uses clause
|
||||||
|
procedure FindUsedUnitReferences(TargetTool: TFindDeclarationTool;
|
||||||
|
SkipComments: boolean; out ListOfPCodeXYPosition: TFPList); // searches all references of TargetTool
|
||||||
|
|
||||||
function CleanPosIsDeclarationIdentifier(CleanPos: integer;
|
function CleanPosIsDeclarationIdentifier(CleanPos: integer;
|
||||||
Node: TCodeTreeNode): boolean;
|
Node: TCodeTreeNode): boolean;
|
||||||
@ -899,6 +906,18 @@ function dbgs(const vat: TVariableAtomType): string; overload;
|
|||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ TFindUsedUnitReferences }
|
||||||
|
|
||||||
|
TFindUsedUnitReferences = class
|
||||||
|
public
|
||||||
|
TargetTool: TFindDeclarationTool;
|
||||||
|
TargetUnitName: string;
|
||||||
|
ListOfPCodeXYPosition: TFPList;
|
||||||
|
Params: TFindDeclarationParams;
|
||||||
|
destructor Destroy; override;
|
||||||
|
end;
|
||||||
|
|
||||||
function dbgs(const Flags: TFindDeclarationFlags): string;
|
function dbgs(const Flags: TFindDeclarationFlags): string;
|
||||||
var
|
var
|
||||||
@ -1203,6 +1222,12 @@ begin
|
|||||||
ListOfPFindContext:=nil;
|
ListOfPFindContext:=nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
destructor TFindUsedUnitReferences.Destroy;
|
||||||
|
begin
|
||||||
|
FreeAndNil(Params);
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TFindDeclarationTool }
|
{ TFindDeclarationTool }
|
||||||
|
|
||||||
function TFindDeclarationTool.FindDeclaration(const CursorPos: TCodeXYPosition;
|
function TFindDeclarationTool.FindDeclaration(const CursorPos: TCodeXYPosition;
|
||||||
@ -4613,7 +4638,7 @@ var
|
|||||||
except
|
except
|
||||||
on E: ECodeToolError do begin
|
on E: ECodeToolError do begin
|
||||||
if E.Sender<>Self then begin
|
if E.Sender<>Self then begin
|
||||||
// there is an error in another unit, which prevetns searching
|
// there is an error in another unit, which prevents searching
|
||||||
// stop further searching in this unit
|
// stop further searching in this unit
|
||||||
raise;
|
raise;
|
||||||
end;
|
end;
|
||||||
@ -5097,6 +5122,55 @@ begin
|
|||||||
Result:=true;
|
Result:=true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TFindDeclarationTool.FindUsedUnitReferences(
|
||||||
|
const CursorPos: TCodeXYPosition; SkipComments: boolean; out
|
||||||
|
ListOfPCodeXYPosition: TFPList);
|
||||||
|
var
|
||||||
|
CleanPos: integer;
|
||||||
|
Node: TCodeTreeNode;
|
||||||
|
UnitInFilename: string;
|
||||||
|
AnUnitName: String;
|
||||||
|
TargetCode: TCodeBuffer;
|
||||||
|
TargetTool: TFindDeclarationTool;
|
||||||
|
begin
|
||||||
|
//debugln(['TFindDeclarationTool.FindUsedUnitReferences ',dbgs(CursorPos)]);
|
||||||
|
ListOfPCodeXYPosition:=nil;
|
||||||
|
BuildTreeAndGetCleanPos(CursorPos,CleanPos);
|
||||||
|
Node:=FindDeepestNodeAtPos(CleanPos,true);
|
||||||
|
if Node.Desc<>ctnUseUnit then
|
||||||
|
RaiseException('This function needs the cursor at a unit in a uses clause');
|
||||||
|
// cursor is on an used unit -> try to locate it
|
||||||
|
MoveCursorToCleanPos(Node.StartPos);
|
||||||
|
ReadNextAtom;
|
||||||
|
AnUnitName:=ExtractUsedUnitNameAtCursor(@UnitInFilename);
|
||||||
|
//debugln(['TFindDeclarationTool.FindUsedUnitReferences Used Unit=',AnUnitName,' in "',UnitInFilename,'"']);
|
||||||
|
TargetCode:=FindUnitSource(AnUnitName,UnitInFilename,true,Node.StartPos);
|
||||||
|
//debugln(['TFindDeclarationTool.FindUsedUnitReferences TargetCode=',TargetCode.Filename]);
|
||||||
|
TargetTool:=FOnGetCodeToolForBuffer(Self,TargetCode,false);
|
||||||
|
FindUsedUnitReferences(TargetTool,SkipComments,ListOfPCodeXYPosition);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TFindDeclarationTool.FindUsedUnitReferences(
|
||||||
|
TargetTool: TFindDeclarationTool; SkipComments: boolean; out
|
||||||
|
ListOfPCodeXYPosition: TFPList);
|
||||||
|
var
|
||||||
|
refs: TFindUsedUnitReferences;
|
||||||
|
begin
|
||||||
|
ListOfPCodeXYPosition:=TFPList.Create;
|
||||||
|
if TargetTool=nil then
|
||||||
|
RaiseException('TargetTool=nil');
|
||||||
|
TargetTool.BuildInterfaceIdentifierCache(true);
|
||||||
|
refs:=TFindUsedUnitReferences.Create;
|
||||||
|
try
|
||||||
|
refs.TargetTool:=TargetTool;
|
||||||
|
refs.TargetUnitName:=TargetTool.GetSourceName(false);
|
||||||
|
refs.ListOfPCodeXYPosition:=ListOfPCodeXYPosition;
|
||||||
|
ForEachIdentifier(SkipComments,@OnFindUsedUnitIdentifier,refs);
|
||||||
|
finally
|
||||||
|
refs.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{-------------------------------------------------------------------------------
|
{-------------------------------------------------------------------------------
|
||||||
function TFindDeclarationTool.CleanPosIsDeclarationIdentifier(CleanPos: integer;
|
function TFindDeclarationTool.CleanPosIsDeclarationIdentifier(CleanPos: integer;
|
||||||
Node: TCodeTreeNode): boolean;
|
Node: TCodeTreeNode): boolean;
|
||||||
@ -9444,6 +9518,64 @@ begin
|
|||||||
until false;
|
until false;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TFindDeclarationTool.OnFindUsedUnitIdentifier(
|
||||||
|
Sender: TPascalParserTool; IdentifierCleanPos: integer; Range: TEPRIRange;
|
||||||
|
Node: TCodeTreeNode; Data: Pointer; var Abort: boolean);
|
||||||
|
var
|
||||||
|
Identifier: PChar;
|
||||||
|
CacheEntry: PInterfaceIdentCacheEntry;
|
||||||
|
refs: TFindUsedUnitReferences;
|
||||||
|
Found: Boolean;
|
||||||
|
ReferencePos: TCodeXYPosition;
|
||||||
|
begin
|
||||||
|
if Range=epriInDirective then exit;
|
||||||
|
if not (Node.Desc in (AllPascalTypes+AllPascalStatements)) then exit;
|
||||||
|
Identifier:=@Src[IdentifierCleanPos];
|
||||||
|
refs:=TFindUsedUnitReferences(Data);
|
||||||
|
CacheEntry:=refs.TargetTool.FInterfaceIdentifierCache.FindIdentifier(Identifier);
|
||||||
|
//debugln(['TFindUsedUnitReferences.OnIdentifier Identifier=',GetIdentifier(Identifier),' Found=',CacheEntry<>nil]);
|
||||||
|
if (CacheEntry=nil)
|
||||||
|
and (CompareIdentifiers(Identifier,PChar(refs.TargetUnitName))<>0) then
|
||||||
|
exit;
|
||||||
|
Sender.MoveCursorToCleanPos(IdentifierCleanPos);
|
||||||
|
Sender.ReadPriorAtom;
|
||||||
|
if (Sender.CurPos.Flag=cafPoint) or (Sender.UpAtomIs('inherited')) then exit;
|
||||||
|
//debugln(['TFindUsedUnitReferences.OnIdentifier Identifier=',GetIdentifier(Identifier),' at begin of term']);
|
||||||
|
// find declaration
|
||||||
|
if refs.Params=nil then
|
||||||
|
refs.Params:=TFindDeclarationParams.Create
|
||||||
|
else
|
||||||
|
refs.Params.Clear;
|
||||||
|
refs.Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors,
|
||||||
|
fdfIgnoreCurContextNode];
|
||||||
|
refs.Params.ContextNode:=Node;
|
||||||
|
//debugln(copy(Src,Params.ContextNode.StartPos,200));
|
||||||
|
refs.Params.SetIdentifier(Self,Identifier,@CheckSrcIdentifier);
|
||||||
|
|
||||||
|
if Range=epriInCode then begin
|
||||||
|
// search identifier in code
|
||||||
|
Found:=FindDeclarationOfIdentAtParam(refs.Params);
|
||||||
|
end else begin
|
||||||
|
// search identifier in comment -> if not found, this is no problem
|
||||||
|
// => silently ignore
|
||||||
|
try
|
||||||
|
Found:=FindDeclarationOfIdentAtParam(refs.Params);
|
||||||
|
except
|
||||||
|
on E: ECodeToolError do begin
|
||||||
|
// continue
|
||||||
|
end;
|
||||||
|
on E: Exception do
|
||||||
|
raise;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
//debugln(['TFindUsedUnitReferences.OnIdentifier Identifier=',GetIdentifier(Identifier),' found=',Found]);
|
||||||
|
|
||||||
|
if not Found then exit;
|
||||||
|
|
||||||
|
if CleanPosToCaret(IdentifierCleanPos,ReferencePos) then
|
||||||
|
AddCodePosition(refs.ListOfPCodeXYPosition,ReferencePos);
|
||||||
|
end;
|
||||||
|
|
||||||
function TFindDeclarationTool.FindNthParameterNode(Node: TCodeTreeNode;
|
function TFindDeclarationTool.FindNthParameterNode(Node: TCodeTreeNode;
|
||||||
ParameterIndex: integer): TCodeTreeNode;
|
ParameterIndex: integer): TCodeTreeNode;
|
||||||
var
|
var
|
||||||
|
@ -51,6 +51,16 @@ type
|
|||||||
);
|
);
|
||||||
TPascalHintModifiers = set of TPascalHintModifier;
|
TPascalHintModifiers = set of TPascalHintModifier;
|
||||||
|
|
||||||
|
TEPRIRange = (
|
||||||
|
epriInCode,
|
||||||
|
epriInComment,
|
||||||
|
epriInDirective
|
||||||
|
);
|
||||||
|
|
||||||
|
TOnEachPRIdentifier = procedure(Sender: TPascalParserTool;
|
||||||
|
IdentifierCleanPos: integer; Range: TEPRIRange;
|
||||||
|
Node: TCodeTreeNode; Data: Pointer; var Abort: boolean) of object;
|
||||||
|
|
||||||
{ TPascalReaderTool }
|
{ TPascalReaderTool }
|
||||||
|
|
||||||
TPascalReaderTool = class(TPascalParserTool)
|
TPascalReaderTool = class(TPascalParserTool)
|
||||||
@ -75,6 +85,14 @@ type
|
|||||||
function ReadStringConstantValue(StartPos: integer): string;
|
function ReadStringConstantValue(StartPos: integer): string;
|
||||||
function GetNodeIdentifier(Node: TCodeTreeNode): PChar;
|
function GetNodeIdentifier(Node: TCodeTreeNode): PChar;
|
||||||
function GetHintModifiers(Node: TCodeTreeNode): TPascalHintModifiers;
|
function GetHintModifiers(Node: TCodeTreeNode): TPascalHintModifiers;
|
||||||
|
procedure ForEachIdentifierInCleanSrc(StartPos, EndPos: integer;
|
||||||
|
SkipComments: boolean; Node: TCodeTreeNode;
|
||||||
|
const OnIdentifier: TOnEachPRIdentifier; Data: pointer;
|
||||||
|
var Abort: boolean); // range in clean source
|
||||||
|
procedure ForEachIdentifierInNode(Node: TCodeTreeNode; SkipComments: boolean;
|
||||||
|
const OnIdentifier: TOnEachPRIdentifier; Data: Pointer; var Abort: boolean); // node and child nodes
|
||||||
|
procedure ForEachIdentifier(SkipComments: boolean;
|
||||||
|
const OnIdentifier: TOnEachPRIdentifier; Data: Pointer); // whole unit/program
|
||||||
|
|
||||||
// properties
|
// properties
|
||||||
function ExtractPropType(PropNode: TCodeTreeNode;
|
function ExtractPropType(PropNode: TCodeTreeNode;
|
||||||
@ -1689,6 +1707,230 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TPascalReaderTool.ForEachIdentifierInCleanSrc(StartPos,
|
||||||
|
EndPos: integer; SkipComments: boolean; Node: TCodeTreeNode;
|
||||||
|
const OnIdentifier: TOnEachPRIdentifier; Data: pointer; var Abort: boolean);
|
||||||
|
var
|
||||||
|
CommentLvl: Integer;
|
||||||
|
InStrConst: Boolean;
|
||||||
|
p: PChar;
|
||||||
|
EndP: Pointer;
|
||||||
|
Range: TEPRIRange;
|
||||||
|
|
||||||
|
procedure SkipIdentifier; inline;
|
||||||
|
begin
|
||||||
|
while (p<EndP) and IsIdentChar[p^] do inc(p);
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
//debugln(['TPascalReaderTool.ForEachIdentifierInCleanSrc Node=',Node.DescAsString,' "',dbgstr(Src,StartPos,EndPos-StartPos),'"']);
|
||||||
|
if StartPos>SrcLen then exit;
|
||||||
|
if EndPos>SrcLen then EndPos:=SrcLen+1;
|
||||||
|
if StartPos>=EndPos then exit;
|
||||||
|
p:=@Src[StartPos];
|
||||||
|
EndP:=p+EndPos-StartPos;
|
||||||
|
while p<EndP do begin
|
||||||
|
case p^ of
|
||||||
|
|
||||||
|
'{':
|
||||||
|
begin
|
||||||
|
inc(p);
|
||||||
|
if p^=#3 then begin
|
||||||
|
// codetools skip comment {#3 #3}
|
||||||
|
inc(p);
|
||||||
|
repeat
|
||||||
|
if p>=EndP then exit;
|
||||||
|
if (p^=#3) and (p[1]='}')
|
||||||
|
then begin
|
||||||
|
inc(p,2);
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
inc(p);
|
||||||
|
until false;
|
||||||
|
end else begin
|
||||||
|
// pascal comment {}
|
||||||
|
CommentLvl:=1;
|
||||||
|
InStrConst:=false;
|
||||||
|
if p^='$' then
|
||||||
|
Range:=epriInDirective
|
||||||
|
else
|
||||||
|
Range:=epriInComment;
|
||||||
|
repeat
|
||||||
|
if p>=EndP then exit;
|
||||||
|
case p^ 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
|
||||||
|
if not SkipComments then begin
|
||||||
|
OnIdentifier(Self,p-PChar(Src)+1,Range,Node,Data,Abort);
|
||||||
|
SkipIdentifier;
|
||||||
|
if Abort then exit;
|
||||||
|
end;
|
||||||
|
while (p<EndP) and IsIdentChar[p^] do inc(p);
|
||||||
|
end;
|
||||||
|
'''':
|
||||||
|
InStrConst:=not InStrConst;
|
||||||
|
#10,#13:
|
||||||
|
InStrConst:=false;
|
||||||
|
end;
|
||||||
|
inc(p);
|
||||||
|
until false;
|
||||||
|
inc(p);
|
||||||
|
//debugln(StartPos,' ',copy(Src,CommentStart,StartPos-CommentStart));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
'/': // Delphi comment
|
||||||
|
if p[1]<>'/' then begin
|
||||||
|
inc(p);
|
||||||
|
end else begin
|
||||||
|
inc(p,2);
|
||||||
|
InStrConst:=false;
|
||||||
|
repeat
|
||||||
|
if p>=EndP then exit;
|
||||||
|
case p^ of
|
||||||
|
#10,#13:
|
||||||
|
break;
|
||||||
|
'a'..'z','A'..'Z','_':
|
||||||
|
if not InStrConst then begin
|
||||||
|
if not SkipComments then begin
|
||||||
|
OnIdentifier(Self,p-PChar(Src)+1,Range,Node,Data,Abort);
|
||||||
|
SkipIdentifier;
|
||||||
|
if Abort then exit;
|
||||||
|
end;
|
||||||
|
while (p<EndP) and IsIdentChar[p^] do inc(p);
|
||||||
|
end;
|
||||||
|
'''':
|
||||||
|
InStrConst:=not InStrConst;
|
||||||
|
end;
|
||||||
|
inc(p);
|
||||||
|
until false;
|
||||||
|
inc(p);
|
||||||
|
if (p<EndP) and (p^ in [#10,#13])
|
||||||
|
and (p[-1]<>p^) then
|
||||||
|
inc(p);
|
||||||
|
end;
|
||||||
|
|
||||||
|
'(': // turbo pascal comment
|
||||||
|
if (p[1]<>'*') then begin
|
||||||
|
inc(p);
|
||||||
|
end else begin
|
||||||
|
inc(p,3);
|
||||||
|
InStrConst:=false;
|
||||||
|
repeat
|
||||||
|
if p>=EndP then exit;
|
||||||
|
case p^ of
|
||||||
|
')':
|
||||||
|
if p[-1]='*' then break;
|
||||||
|
'a'..'z','A'..'Z','_':
|
||||||
|
if not InStrConst then begin
|
||||||
|
if not SkipComments then begin
|
||||||
|
OnIdentifier(Self,p-PChar(Src)+1,Range,Node,Data,Abort);
|
||||||
|
SkipIdentifier;
|
||||||
|
if Abort then exit;
|
||||||
|
end;
|
||||||
|
SkipIdentifier;
|
||||||
|
end;
|
||||||
|
'''':
|
||||||
|
InStrConst:=not InStrConst;
|
||||||
|
#10,#13:
|
||||||
|
InStrConst:=false;
|
||||||
|
end;
|
||||||
|
inc(p);
|
||||||
|
until false;
|
||||||
|
inc(p);
|
||||||
|
end;
|
||||||
|
|
||||||
|
'a'..'z','A'..'Z','_':
|
||||||
|
begin
|
||||||
|
OnIdentifier(Self,p-PChar(Src)+1,epriInCode,Node,Data,Abort);
|
||||||
|
SkipIdentifier;
|
||||||
|
if Abort then exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
'''':
|
||||||
|
begin
|
||||||
|
// skip string constant
|
||||||
|
inc(p);
|
||||||
|
while p<EndP do begin
|
||||||
|
if (not (p^ in ['''',#10,#13])) then
|
||||||
|
inc(p)
|
||||||
|
else begin
|
||||||
|
inc(p);
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
else
|
||||||
|
inc(p);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TPascalReaderTool.ForEachIdentifierInNode(Node: TCodeTreeNode;
|
||||||
|
SkipComments: boolean; const OnIdentifier: TOnEachPRIdentifier;
|
||||||
|
Data: Pointer; var Abort: boolean);
|
||||||
|
var
|
||||||
|
StartPos: Integer;
|
||||||
|
EndPos: Integer;
|
||||||
|
Child: TCodeTreeNode;
|
||||||
|
begin
|
||||||
|
//debugln(['TPascalReaderTool.ForEachIdentifierInNode START ',Node.DescAsString]);
|
||||||
|
if NodeNeedsBuildSubTree(Node) then
|
||||||
|
BuildSubTree(Node);
|
||||||
|
if Node.FirstChild<>nil then begin
|
||||||
|
EndPos:=Node.StartPos;
|
||||||
|
Child:=Node.FirstChild;
|
||||||
|
while Child<>nil do begin
|
||||||
|
// scan in front of child
|
||||||
|
ForEachIdentifierInCleanSrc(EndPos,Child.StartPos,SkipComments,
|
||||||
|
Node,OnIdentifier,Data,Abort);
|
||||||
|
if Abort then exit;
|
||||||
|
// scan child
|
||||||
|
ForEachIdentifierInNode(Child,SkipComments,OnIdentifier,Data,Abort);
|
||||||
|
if Abort then exit;
|
||||||
|
EndPos:=Child.EndPos;
|
||||||
|
Child:=Child.NextBrother;
|
||||||
|
end;
|
||||||
|
// scan behind children
|
||||||
|
ForEachIdentifierInCleanSrc(EndPos,Node.EndPos,SkipComments,
|
||||||
|
Node,OnIdentifier,Data,Abort);
|
||||||
|
end else begin
|
||||||
|
// leaf node
|
||||||
|
StartPos:=Node.StartPos;
|
||||||
|
EndPos:=Node.EndPos;
|
||||||
|
// nodes without children can overlap with their NextBrother
|
||||||
|
if (Node.NextBrother<>nil)
|
||||||
|
and (Node.NextBrother.StartPos<EndPos) then
|
||||||
|
EndPos:=Node.NextBrother.StartPos;
|
||||||
|
// scan node range
|
||||||
|
ForEachIdentifierInCleanSrc(StartPos,EndPos,SkipComments,
|
||||||
|
Node,OnIdentifier,Data,Abort);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TPascalReaderTool.ForEachIdentifier(SkipComments: boolean;
|
||||||
|
const OnIdentifier: TOnEachPRIdentifier; Data: Pointer);
|
||||||
|
var
|
||||||
|
Node: TCodeTreeNode;
|
||||||
|
Abort: boolean;
|
||||||
|
begin
|
||||||
|
//debugln(['TPascalReaderTool.ForEachIdentifier START']);
|
||||||
|
Node:=Tree.Root;
|
||||||
|
Abort:=false;
|
||||||
|
while Node<>nil do begin
|
||||||
|
ForEachIdentifierInNode(Node,SkipComments,OnIdentifier,Data,Abort);
|
||||||
|
if Abort then exit;
|
||||||
|
Node:=Node.NextBrother;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TPascalReaderTool.FindVarNode(StartNode: TCodeTreeNode;
|
function TPascalReaderTool.FindVarNode(StartNode: TCodeTreeNode;
|
||||||
const UpperVarName: string): TCodeTreeNode;
|
const UpperVarName: string): TCodeTreeNode;
|
||||||
var
|
var
|
||||||
|
Loading…
Reference in New Issue
Block a user