mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-11-06 02:59:30 +01:00
codetools: implemented FindCodeContext for procedures
git-svn-id: trunk@9296 -
This commit is contained in:
parent
8bb640c7fd
commit
d15d5a84e9
3
.gitattributes
vendored
3
.gitattributes
vendored
@ -64,12 +64,15 @@ components/codetools/examples/finddeclaration.lpi svneol=native#text/plain
|
||||
components/codetools/examples/finddeclaration.lpr svneol=native#text/plain
|
||||
components/codetools/examples/fixfilenames.lpi svneol=native#text/plain
|
||||
components/codetools/examples/fixfilenames.pas svneol=native#text/plain
|
||||
components/codetools/examples/getcontext.lpi svneol=native#text/plain
|
||||
components/codetools/examples/getcontext.lpr svneol=native#text/plain
|
||||
components/codetools/examples/methodjumping.lpi svneol=native#text/plain
|
||||
components/codetools/examples/methodjumping.pas svneol=native#text/plain
|
||||
components/codetools/examples/scanexamples/BigLettersUnit.pas svneol=native#text/plain
|
||||
components/codetools/examples/scanexamples/brokenfilenames.pas svneol=native#text/plain
|
||||
components/codetools/examples/scanexamples/brokenincfiles.inc svneol=native#text/plain
|
||||
components/codetools/examples/scanexamples/empty.inc svneol=native#text/plain
|
||||
components/codetools/examples/scanexamples/getcontextexample.pas svneol=native#text/plain
|
||||
components/codetools/examples/scanexamples/simpleunit1.pas svneol=native#text/plain
|
||||
components/codetools/examples/scanexamples/tgeneric2.pas svneol=native#text/plain
|
||||
components/codetools/expreval.pas svneol=native#text/pascal
|
||||
|
||||
@ -2661,7 +2661,7 @@ var CleanCursorPos, Indent, insertPos: integer;
|
||||
Params.OnTopLvlIdentifierFound:=@OnTopLvlIdentifierFound;
|
||||
Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors,
|
||||
fdfTopLvlResolving,fdfFindVariable];
|
||||
if (not FindDeclarationOfIdentAtCursor(Params))
|
||||
if (not FindDeclarationOfIdentAtParam(Params))
|
||||
or (Params.NewNode.Desc<>ctnProperty) then begin
|
||||
{$IFDEF CTDEBUG}
|
||||
DebugLn('FindEventTypeAtCursor not a property');
|
||||
|
||||
48
components/codetools/examples/getcontext.lpi
Normal file
48
components/codetools/examples/getcontext.lpi
Normal file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.0"?>
|
||||
<CONFIG>
|
||||
<ProjectOptions>
|
||||
<PathDelim Value="/"/>
|
||||
<Version Value="5"/>
|
||||
<General>
|
||||
<SessionStorage Value="InProjectDir"/>
|
||||
<MainUnit Value="0"/>
|
||||
<IconPath Value="./"/>
|
||||
<TargetFileExt Value=""/>
|
||||
</General>
|
||||
<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>
|
||||
<Units Count="2">
|
||||
<Unit0>
|
||||
<Filename Value="getcontext.lpr"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="GetContext"/>
|
||||
</Unit0>
|
||||
<Unit1>
|
||||
<Filename Value="scanexamples/getcontextexample.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="GetContextExample"/>
|
||||
</Unit1>
|
||||
</Units>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
<Version Value="5"/>
|
||||
<SearchPaths>
|
||||
<OtherUnitFiles Value="$(LazarusDir)/components/codetools/units/$(TargetCPU)-$(TargetOS)/;scanexamples/"/>
|
||||
</SearchPaths>
|
||||
<CodeGeneration>
|
||||
<Generate Value="Faster"/>
|
||||
</CodeGeneration>
|
||||
<Other>
|
||||
<CompilerPath Value="$(CompPath)"/>
|
||||
</Other>
|
||||
</CompilerOptions>
|
||||
</CONFIG>
|
||||
68
components/codetools/examples/getcontext.lpr
Normal file
68
components/codetools/examples/getcontext.lpr
Normal file
@ -0,0 +1,68 @@
|
||||
program GetContext;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
uses
|
||||
Classes, SysUtils, CodeCache, CodeToolManager, DefineTemplates,
|
||||
CodeToolsConfig, GetContextExample, IdentCompletionTool, FindDeclarationTool;
|
||||
|
||||
const
|
||||
ConfigFilename = 'codetools.config';
|
||||
var
|
||||
Options: TCodeToolsOptions;
|
||||
Code: TCodeBuffer;
|
||||
CodeContexts: TCodeContextInfo;
|
||||
i: Integer;
|
||||
ExprType: TExpressionType;
|
||||
begin
|
||||
// setup the Options
|
||||
Options:=TCodeToolsOptions.Create;
|
||||
|
||||
// To not parse the FPC sources every time, the options are saved to a file.
|
||||
if FileExists(ConfigFilename) then
|
||||
Options.LoadFromFile(ConfigFilename);
|
||||
|
||||
// setup your paths
|
||||
Options.FPCPath:='/usr/bin/ppc386';
|
||||
Options.FPCSrcDir:=ExpandFileName('~/freepascal/fpc');
|
||||
Options.LazarusSrcDir:=ExpandFileName('~/pascal/lazarus');
|
||||
|
||||
// optional: ProjectDir and TestPascalFile exists only to easily test some
|
||||
// things.
|
||||
Options.ProjectDir:=GetCurrentDir+'/scanexamples/';
|
||||
Options.TestPascalFile:=Options.ProjectDir+'getcontextexample.pas';
|
||||
|
||||
// init the codetools
|
||||
if not Options.UnitLinkListValid then
|
||||
writeln('Scanning FPC sources may take a while ...');
|
||||
CodeToolBoss.Init(Options);
|
||||
|
||||
// save the options and the FPC unit links results.
|
||||
Options.SaveToFile(ConfigFilename);
|
||||
|
||||
// Example: find declaration of 'TObject'
|
||||
|
||||
// Step 1: load the file
|
||||
Code:=CodeToolBoss.LoadFile(Options.TestPascalFile,false,false);
|
||||
if Code=nil then
|
||||
raise Exception.Create('loading failed '+Options.TestPascalFile);
|
||||
|
||||
// Step 2: find context
|
||||
if CodeToolBoss.FindCodeContext(Code,7,14,CodeContexts) then
|
||||
begin
|
||||
writeln('Contexts found: Count=',CodeContexts.Count);
|
||||
for i:=0 to CodeContexts.Count-1 do begin
|
||||
ExprType:=CodeContexts[i];
|
||||
write('i=',i,' ',ExprTypeToString(ExprType));
|
||||
if ExprType.Context.Node<>nil then
|
||||
write(' ',ExprType.Context.Tool.ExtractNode(ExprType.Context.Node,[]));
|
||||
writeln;
|
||||
end;
|
||||
end else begin
|
||||
writeln('Contexts not found: ',CodeToolBoss.ErrorMessage);
|
||||
end;
|
||||
CodeContexts.Free;
|
||||
|
||||
Options.Free;
|
||||
end.
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
unit GetContextExample;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils;
|
||||
|
||||
implementation
|
||||
|
||||
procedure CallOverloadedProc;
|
||||
begin
|
||||
Pos('','');
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
@ -366,7 +366,7 @@ var
|
||||
{$IFDEF CTDebug}
|
||||
DebugLn('AddVariableAtCursor Searching ',GetIdentifier(Params.Identifier));
|
||||
{$ENDIF}
|
||||
if not FindDeclarationOfIdentAtCursor(Params) then begin
|
||||
if not FindDeclarationOfIdentAtParam(Params) then begin
|
||||
{$IFDEF CTDebug}
|
||||
DebugLn('AddVariableAtCursor B not found');
|
||||
{$ENDIF}
|
||||
|
||||
@ -496,23 +496,6 @@ const
|
||||
AllFindSmartFlags = [fsfIncludeDirective];
|
||||
|
||||
type
|
||||
|
||||
{ TCodeContextInfo }
|
||||
|
||||
TCodeContextInfo = class
|
||||
private
|
||||
FItems: PExpressionType;
|
||||
FCount: integer;
|
||||
function GetItems(Index: integer): TExpressionType;
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
function Count: integer;
|
||||
property Items[Index: integer]: TExpressionType read GetItems; default;
|
||||
function Add(const Context: TExpressionType): integer;
|
||||
procedure Clear;
|
||||
end;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
ECodeToolUnitNotFound = class(ECodeToolFileNotFound)
|
||||
end;
|
||||
@ -617,7 +600,7 @@ type
|
||||
protected
|
||||
function CheckSrcIdentifier(Params: TFindDeclarationParams;
|
||||
const FoundContext: TFindContext): TIdentifierFoundResult;
|
||||
function FindDeclarationOfIdentAtCursor(
|
||||
function FindDeclarationOfIdentAtParam(
|
||||
Params: TFindDeclarationParams): boolean;
|
||||
function IdentifierIsDefined(IdentAtom: TAtomPosition;
|
||||
ContextNode: TCodeTreeNode; Params: TFindDeclarationParams): boolean;
|
||||
@ -729,8 +712,6 @@ type
|
||||
|
||||
function CleanPosIsDeclarationIdentifier(CleanPos: integer;
|
||||
Node: TCodeTreeNode): boolean;
|
||||
function FindCodeContext(const CursorPos: TCodeXYPosition;
|
||||
out CodeContexts: TCodeContextInfo): boolean;
|
||||
|
||||
function JumpToNode(ANode: TCodeTreeNode;
|
||||
var NewPos: TCodeXYPosition; var NewTopLine: integer;
|
||||
@ -1289,7 +1270,7 @@ begin
|
||||
fdfTopLvlResolving,fdfSearchInAncestors];
|
||||
if not DirectSearch then begin
|
||||
// ToDo: DirtySrc
|
||||
Result:=FindDeclarationOfIdentAtCursor(Params);
|
||||
Result:=FindDeclarationOfIdentAtParam(Params);
|
||||
end else begin
|
||||
Include(Params.Flags,fdfIgnoreCurContextNode);
|
||||
if SearchForward then
|
||||
@ -1881,7 +1862,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TFindDeclarationTool.FindDeclarationOfIdentAtCursor(
|
||||
function TFindDeclarationTool.FindDeclarationOfIdentAtParam(
|
||||
Params: TFindDeclarationParams): boolean;
|
||||
{ searches an identifier in clean code, parses code in front and after the
|
||||
identifier
|
||||
@ -1902,7 +1883,7 @@ var
|
||||
ExprType: TExpressionType;
|
||||
begin
|
||||
{$IFDEF CTDEBUG}
|
||||
DebugLn('[TFindDeclarationTool.FindDeclarationOfIdentAtCursor] Identifier=',
|
||||
DebugLn('[TFindDeclarationTool.FindDeclarationOfIdentAtParam] Identifier=',
|
||||
'"',GetIdentifier(Params.Identifier),'"',
|
||||
' ContextNode=',NodeDescriptionAsString(Params.ContextNode.Desc),
|
||||
' "',copy(Src,Params.ContextNode.StartPos,20),'"');
|
||||
@ -1927,7 +1908,7 @@ begin
|
||||
Params.SetResult(CleanFindContext);
|
||||
end;
|
||||
{$IFDEF CTDEBUG}
|
||||
DbgOut('[TFindDeclarationTool.FindDeclarationOfIdentAtCursor] Ident=',
|
||||
DbgOut('[TFindDeclarationTool.FindDeclarationOfIdentAtParam] Ident=',
|
||||
'"',GetIdentifier(Params.Identifier),'" ');
|
||||
if Params.NewNode<>nil then
|
||||
DebugLn('Node=',Params.NewNode.DescAsString,' ',Params.NewCodeTool.MainFilename)
|
||||
@ -3279,7 +3260,7 @@ var
|
||||
if fdfSearchForward in Params.Flags then
|
||||
Found:=FindIdentifierInContext(Params)
|
||||
else
|
||||
Found:=FindDeclarationOfIdentAtCursor(Params);
|
||||
Found:=FindDeclarationOfIdentAtParam(Params);
|
||||
except
|
||||
on E: ECodeToolError do
|
||||
if not IsComment then raise;
|
||||
@ -3590,100 +3571,6 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TFindDeclarationTool.FindCodeContext(const CursorPos: TCodeXYPosition;
|
||||
out CodeContexts: TCodeContextInfo): boolean;
|
||||
var
|
||||
CleanCursorPos: integer;
|
||||
CursorNode: TCodeTreeNode;
|
||||
Params: TFindDeclarationParams;
|
||||
|
||||
procedure AddContext(Tool: TFindDeclarationTool; Node: TCodeTreeNode);
|
||||
begin
|
||||
if CodeContexts=nil then
|
||||
CodeContexts:=TCodeContextInfo.Create;
|
||||
CodeContexts.Add(CreateExpressionType(xtContext,xtNone,
|
||||
CreateFindContext(Tool,Node)));
|
||||
//DebugLn('AddContext ',node.DescAsString,' ',copy(Src,Node.StartPos,Node.EndPos-Node.StartPos));
|
||||
end;
|
||||
|
||||
function CheckContextIsParameter(var Ok: boolean): boolean;
|
||||
// returns true, on error or context is parameter
|
||||
// returns false, if no error and context is not parameter
|
||||
var
|
||||
VarNameAtom, ProcNameAtom: TAtomPosition;
|
||||
ParameterIndex: integer;
|
||||
ParameterNode: TCodeTreeNode;
|
||||
begin
|
||||
Result:=false;
|
||||
//DebugLn('CheckContextIsParameter ');
|
||||
if not CheckParameterSyntax(CursorNode, CleanCursorPos,
|
||||
VarNameAtom, ProcNameAtom, ParameterIndex) then exit;
|
||||
if VarNameAtom.StartPos<1 then exit;
|
||||
// it is a parameter
|
||||
Result:=true;
|
||||
ok:=true;
|
||||
// find declaration of parameter list
|
||||
Params.ContextNode:=CursorNode;
|
||||
Params.SetIdentifier(Self,@Src[ProcNameAtom.StartPos],@CheckSrcIdentifier);
|
||||
Params.Flags:=fdfGlobals+[fdfSearchInParentNodes,fdfSearchInAncestors,
|
||||
fdfFindVariable,fdfIgnoreCurContextNode];
|
||||
//DebugLn('CheckContextIsParameter searching procedure ...');
|
||||
if not FindIdentifierInContext(Params) then exit;
|
||||
if Params.NewNode<>nil then begin
|
||||
//DebugLn('CheckContextIsParameter searching parameter node ...');
|
||||
ParameterNode:=Params.NewCodeTool.FindNthParameterNode(Params.NewNode,
|
||||
ParameterIndex);
|
||||
if ParameterNode<>nil then begin
|
||||
//DebugLn('CheckContextIsParameter adding parameter node to CodeContexts');
|
||||
AddContext(Params.NewCodeTool,ParameterNode);
|
||||
|
||||
end;
|
||||
//DebugLn(' CompleteLocalVariableAsParameter Dont know: ',Params.NewNode.DescAsString);
|
||||
end;
|
||||
end;
|
||||
|
||||
begin
|
||||
CodeContexts:=nil;
|
||||
Result:=false;
|
||||
ActivateGlobalWriteLock;
|
||||
Params:=TFindDeclarationParams.Create;
|
||||
try
|
||||
// build code tree
|
||||
{$IFDEF CTDEBUG}
|
||||
DebugLn('TFindDeclarationTool.FindCodeContext A CursorPos=X',dbgs(CursorPos.X),',Y',dbgs(CursorPos.Y));
|
||||
{$ENDIF}
|
||||
if DirtySrc<>nil then DirtySrc.Clear;
|
||||
BuildTreeAndGetCleanPos(trTillCursor,CursorPos,CleanCursorPos,
|
||||
[{$IFNDEF DisableIgnoreErrorAfter}btSetIgnoreErrorPos,{$ENDIF}
|
||||
btLoadDirtySource,btCursorPosOutAllowed]);
|
||||
{$IFDEF CTDEBUG}
|
||||
DebugLn('TFindDeclarationTool.FindCodeContext C CleanCursorPos=',dbgs(CleanCursorPos));
|
||||
{$ENDIF}
|
||||
// find CodeTreeNode at cursor
|
||||
if (Tree.Root<>nil) and (Tree.Root.StartPos<=CleanCursorPos) then begin
|
||||
CursorNode:=BuildSubTreeAndFindDeepestNodeAtPos(Tree.Root,CleanCursorPos,
|
||||
true);
|
||||
end else begin
|
||||
CursorNode:=nil;
|
||||
end;
|
||||
|
||||
if CursorNode<>nil then begin
|
||||
if CheckContextIsParameter(Result) then exit;
|
||||
end;
|
||||
|
||||
if CodeContexts=nil then begin
|
||||
// create default
|
||||
AddContext(Self,CursorNode);
|
||||
end;
|
||||
|
||||
Result:=true;
|
||||
finally
|
||||
Params.Free;
|
||||
DeactivateGlobalWriteLock;
|
||||
end;
|
||||
Result:=false;
|
||||
end;
|
||||
|
||||
function TFindDeclarationTool.JumpToNode(ANode: TCodeTreeNode;
|
||||
var NewPos: TCodeXYPosition; var NewTopLine: integer;
|
||||
IgnoreJumpCentered: boolean): boolean;
|
||||
@ -7879,42 +7766,5 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
{ TCodeContextInfo }
|
||||
|
||||
function TCodeContextInfo.GetItems(Index: integer): TExpressionType;
|
||||
begin
|
||||
Result:=FItems[Index];
|
||||
end;
|
||||
|
||||
constructor TCodeContextInfo.Create;
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
destructor TCodeContextInfo.Destroy;
|
||||
begin
|
||||
Clear;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TCodeContextInfo.Count: integer;
|
||||
begin
|
||||
Result:=FCount;
|
||||
end;
|
||||
|
||||
function TCodeContextInfo.Add(const Context: TExpressionType): integer;
|
||||
begin
|
||||
inc(FCount);
|
||||
Result:=Count;
|
||||
ReAllocMem(FItems,SizeOf(TExpressionType)*FCount);
|
||||
FItems[FCount-1]:=Context;
|
||||
end;
|
||||
|
||||
procedure TCodeContextInfo.Clear;
|
||||
begin
|
||||
FCount:=0;
|
||||
ReAllocMem(FItems,0);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
||||
@ -209,6 +209,32 @@ type
|
||||
property Capacity: integer read FCapacity write SetCapacity;
|
||||
end;
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
{ TCodeContextInfo }
|
||||
|
||||
TCodeContextInfo = class
|
||||
private
|
||||
FEndPos: integer;
|
||||
FItems: PExpressionType;
|
||||
FCount: integer;
|
||||
FParameterIndex: integer;
|
||||
FProcName: string;
|
||||
FStartPos: integer;
|
||||
function GetItems(Index: integer): TExpressionType;
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
function Count: integer;
|
||||
property Items[Index: integer]: TExpressionType read GetItems; default;
|
||||
function Add(const Context: TExpressionType): integer;
|
||||
procedure Clear;
|
||||
property ParameterIndex: integer read FParameterIndex write FParameterIndex;// 1 based
|
||||
property ProcName: string read FProcName write FProcName;
|
||||
property StartPos: integer read FStartPos write FStartPos;// context is valid from StartPos to EndPos
|
||||
property EndPos: integer read FEndPos write FEndPos;
|
||||
end;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// TIdentCompletionTool
|
||||
|
||||
@ -221,6 +247,7 @@ type
|
||||
// property names in source)
|
||||
protected
|
||||
CurrentIdentifierList: TIdentifierList;
|
||||
CurrentContexts: TCodeContextInfo;
|
||||
function CollectAllIdentifiers(Params: TFindDeclarationParams;
|
||||
const FoundContext: TFindContext): TIdentifierFoundResult;
|
||||
procedure GatherPredefinedIdentifiers(CleanPos: integer;
|
||||
@ -230,10 +257,25 @@ type
|
||||
procedure GatherUnitnames(CleanPos: integer;
|
||||
const Context: TFindContext; BeautifyCodeOptions: TBeautifyCodeOptions);
|
||||
procedure GatherSourceNames(const Context: TFindContext);
|
||||
procedure InitCollectIdentifiers(const CursorPos: TCodeXYPosition;
|
||||
var IdentifierList: TIdentifierList);
|
||||
procedure ParseSourceTillCollectionStart(const CursorPos: TCodeXYPosition;
|
||||
out CleanCursorPos: integer; out CursorNode: TCodeTreeNode;
|
||||
out IdentStartPos, IdentEndPos: integer);
|
||||
procedure FindCollectionContext(Params: TFindDeclarationParams;
|
||||
IdentStartPos: integer; CursorNode: TCodeTreeNode;
|
||||
out GatherContext: TFindContext; out ContextExprStartPos: LongInt;
|
||||
out StartInSubContext: Boolean);
|
||||
function CollectAllContexts(Params: TFindDeclarationParams;
|
||||
const FoundContext: TFindContext): TIdentifierFoundResult;
|
||||
procedure AddCollectionContext(Tool: TFindDeclarationTool;
|
||||
Node: TCodeTreeNode);
|
||||
public
|
||||
function GatherIdentifiers(const CursorPos: TCodeXYPosition;
|
||||
var IdentifierList: TIdentifierList;
|
||||
BeautifyCodeOptions: TBeautifyCodeOptions): boolean;
|
||||
function FindCodeContext(const CursorPos: TCodeXYPosition;
|
||||
out CodeContexts: TCodeContextInfo): boolean;
|
||||
end;
|
||||
|
||||
const
|
||||
@ -1087,10 +1129,50 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TIdentCompletionTool.GatherIdentifiers(
|
||||
const CursorPos: TCodeXYPosition; var IdentifierList: TIdentifierList;
|
||||
BeautifyCodeOptions: TBeautifyCodeOptions): boolean;
|
||||
|
||||
procedure TIdentCompletionTool.InitCollectIdentifiers(
|
||||
const CursorPos: TCodeXYPosition; var IdentifierList: TIdentifierList);
|
||||
begin
|
||||
if IdentifierList=nil then IdentifierList:=TIdentifierList.Create;
|
||||
CurrentIdentifierList:=IdentifierList;
|
||||
CurrentIdentifierList.Clear;
|
||||
LastGatheredIdentParent:=nil;
|
||||
LastGatheredIdentLevel:=0;
|
||||
CurrentIdentifierList.StartContextPos:=CursorPos;
|
||||
CurrentIdentifierList.StartContext.Tool:=Self;
|
||||
end;
|
||||
|
||||
procedure TIdentCompletionTool.ParseSourceTillCollectionStart(
|
||||
const CursorPos: TCodeXYPosition; out CleanCursorPos: integer;
|
||||
out CursorNode: TCodeTreeNode; out IdentStartPos, IdentEndPos: integer);
|
||||
begin
|
||||
CleanCursorPos:=0;
|
||||
CursorNode:=nil;
|
||||
IdentStartPos:=0;
|
||||
IdentEndPos:=0;
|
||||
|
||||
// build code tree
|
||||
{$IFDEF CTDEBUG}
|
||||
DebugLn('TIdentCompletionTool.GatherIdentifiers A CursorPos=',dbgs(CursorPos.X),',',dbgs(CursorPos.Y));
|
||||
{$ENDIF}
|
||||
BuildTreeAndGetCleanPos(trTillCursor,CursorPos,CleanCursorPos,
|
||||
[{$IFNDEF DisableIgnoreErrorAfter}btSetIgnoreErrorPos{$ENDIF}]);
|
||||
|
||||
// find node at position
|
||||
CursorNode:=FindDeepestExpandedNodeAtPos(CleanCursorPos,true);
|
||||
if CurrentIdentifierList<>nil then
|
||||
CurrentIdentifierList.StartContext.Node:=CursorNode;
|
||||
|
||||
// get identifier position
|
||||
GetIdentStartEndAtPosition(Src,CleanCursorPos,IdentStartPos,IdentEndPos);
|
||||
end;
|
||||
|
||||
procedure TIdentCompletionTool.FindCollectionContext(
|
||||
Params: TFindDeclarationParams; IdentStartPos: integer;
|
||||
CursorNode: TCodeTreeNode;
|
||||
out GatherContext: TFindContext;
|
||||
out ContextExprStartPos: LongInt;
|
||||
out StartInSubContext: Boolean);
|
||||
|
||||
function GetContextExprStartPos(IdentStartPos: integer;
|
||||
ContextNode: TCodeTreeNode): integer;
|
||||
begin
|
||||
@ -1109,45 +1191,83 @@ function TIdentCompletionTool.GatherIdentifiers(
|
||||
Result:=IdentStartPos;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
var
|
||||
ExprType: TExpressionType;
|
||||
begin
|
||||
GatherContext:=CreateFindContext(Self,CursorNode);
|
||||
|
||||
ContextExprStartPos:=GetContextExprStartPos(IdentStartPos,CursorNode);
|
||||
if GatherContext.Node.Desc=ctnWithVariable then
|
||||
GatherContext.Node:=GatherContext.Node.Parent;
|
||||
|
||||
StartInSubContext:=false;
|
||||
if ContextExprStartPos<IdentStartPos then begin
|
||||
MoveCursorToCleanPos(IdentStartPos);
|
||||
Params.ContextNode:=CursorNode;
|
||||
Params.SetIdentifier(Self,nil,nil);
|
||||
Params.Flags:=[fdfExceptionOnNotFound,
|
||||
fdfSearchInParentNodes,fdfSearchInAncestors];
|
||||
ExprType:=FindExpressionTypeOfVariable(ContextExprStartPos,IdentStartPos,
|
||||
Params);
|
||||
if (ExprType.Desc=xtContext) then begin
|
||||
GatherContext:=ExprType.Context;
|
||||
StartInSubContext:=true;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TIdentCompletionTool.CollectAllContexts(
|
||||
Params: TFindDeclarationParams; const FoundContext: TFindContext
|
||||
): TIdentifierFoundResult;
|
||||
begin
|
||||
Result:=ifrProceedSearch;
|
||||
if FoundContext.Node=nil then exit;
|
||||
case FoundContext.Node.Desc of
|
||||
ctnProcedure:
|
||||
begin
|
||||
if (CurrentContexts.ProcName='') then exit;
|
||||
FoundContext.Tool.MoveCursorToProcName(FoundContext.Node,true);
|
||||
if not FoundContext.Tool.CompareSrcIdentifier(
|
||||
FoundContext.Tool.CurPos.StartPos,
|
||||
CurrentContexts.ProcName) then exit;
|
||||
end;
|
||||
else
|
||||
exit;
|
||||
end;
|
||||
AddCollectionContext(FoundContext.Tool,FoundContext.Node);
|
||||
end;
|
||||
|
||||
procedure TIdentCompletionTool.AddCollectionContext(Tool: TFindDeclarationTool;
|
||||
Node: TCodeTreeNode);
|
||||
begin
|
||||
if CurrentContexts=nil then
|
||||
CurrentContexts:=TCodeContextInfo.Create;
|
||||
CurrentContexts.Add(CreateExpressionType(xtContext,xtNone,
|
||||
CreateFindContext(Tool,Node)));
|
||||
//DebugLn('TIdentCompletionTool.AddCollectionContext ',Node.DescAsString,' ',ExtractNode(Node,[]));
|
||||
end;
|
||||
|
||||
function TIdentCompletionTool.GatherIdentifiers(
|
||||
const CursorPos: TCodeXYPosition; var IdentifierList: TIdentifierList;
|
||||
BeautifyCodeOptions: TBeautifyCodeOptions): boolean;
|
||||
var
|
||||
CleanCursorPos, IdentStartPos, IdentEndPos: integer;
|
||||
CursorNode: TCodeTreeNode;
|
||||
Params: TFindDeclarationParams;
|
||||
GatherContext: TFindContext;
|
||||
ExprType: TExpressionType;
|
||||
ContextExprStartPos: Integer;
|
||||
StartInSubContext: Boolean;
|
||||
StartPosOfVariable: LongInt;
|
||||
begin
|
||||
Result:=false;
|
||||
if IdentifierList=nil then IdentifierList:=TIdentifierList.Create;
|
||||
CurrentIdentifierList:=IdentifierList;
|
||||
CurrentIdentifierList.Clear;
|
||||
LastGatheredIdentParent:=nil;
|
||||
LastGatheredIdentLevel:=0;
|
||||
CurrentIdentifierList.StartContextPos:=CursorPos;
|
||||
CurrentIdentifierList.StartContext.Tool:=Self;
|
||||
|
||||
|
||||
ActivateGlobalWriteLock;
|
||||
Params:=TFindDeclarationParams.Create;
|
||||
try
|
||||
// build code tree
|
||||
{$IFDEF CTDEBUG}
|
||||
DebugLn('TIdentCompletionTool.GatherIdentifiers A CursorPos=',dbgs(CursorPos.X),',',dbgs(CursorPos.Y));
|
||||
{$ENDIF}
|
||||
BuildTreeAndGetCleanPos(trTillCursor,CursorPos,CleanCursorPos,
|
||||
[{$IFNDEF DisableIgnoreErrorAfter}btSetIgnoreErrorPos{$ENDIF}]);
|
||||
|
||||
// find node at position
|
||||
CursorNode:=FindDeepestExpandedNodeAtPos(CleanCursorPos,true);
|
||||
CurrentIdentifierList.StartContext.Node:=CursorNode;
|
||||
|
||||
// find class and ancestors if existing (needed for protected identifiers)
|
||||
FindContextClassAndAncestors(CursorPos,ClassAndAncestors);
|
||||
|
||||
// get identifier position
|
||||
GetIdentStartEndAtPosition(Src,CleanCursorPos,IdentStartPos,IdentEndPos);
|
||||
InitCollectIdentifiers(CursorPos,IdentifierList);
|
||||
ParseSourceTillCollectionStart(CursorPos,CleanCursorPos,CursorNode,
|
||||
IdentStartPos,IdentEndPos);
|
||||
|
||||
// find context
|
||||
{$IFDEF CTDEBUG}
|
||||
@ -1162,30 +1282,11 @@ begin
|
||||
end else if CursorNode.Desc in AllSourceTypes then begin
|
||||
GatherSourceNames(GatherContext);
|
||||
end else begin
|
||||
ContextExprStartPos:=GetContextExprStartPos(IdentStartPos,CursorNode);
|
||||
if GatherContext.Node.Desc=ctnWithVariable then
|
||||
GatherContext.Node:=GatherContext.Node.Parent;
|
||||
// find class and ancestors if existing (needed for protected identifiers)
|
||||
FindContextClassAndAncestors(CursorPos,ClassAndAncestors);
|
||||
|
||||
{$IFDEF CTDEBUG}
|
||||
DebugLn('TIdentCompletionTool.GatherIdentifiers C',
|
||||
' ContextExprStartPos=',dbgs(ContextExprStartPos),
|
||||
' Expr=',StringToPascalConst(copy(Src,ContextExprStartPos,
|
||||
IdentStartPos-ContextExprStartPos)));
|
||||
{$ENDIF}
|
||||
StartInSubContext:=false;
|
||||
if ContextExprStartPos<IdentStartPos then begin
|
||||
MoveCursorToCleanPos(IdentStartPos);
|
||||
Params.ContextNode:=CursorNode;
|
||||
Params.SetIdentifier(Self,nil,nil);
|
||||
Params.Flags:=[fdfExceptionOnNotFound,
|
||||
fdfSearchInParentNodes,fdfSearchInAncestors];
|
||||
ExprType:=FindExpressionTypeOfVariable(ContextExprStartPos,IdentStartPos,
|
||||
Params);
|
||||
if (ExprType.Desc=xtContext) then begin
|
||||
GatherContext:=ExprType.Context;
|
||||
StartInSubContext:=true;
|
||||
end;
|
||||
end;
|
||||
FindCollectionContext(Params,IdentStartPos,CursorNode,
|
||||
GatherContext,ContextExprStartPos,StartInSubContext);
|
||||
|
||||
// search and gather identifiers in context
|
||||
if (GatherContext.Tool<>nil) and (GatherContext.Node<>nil) then begin
|
||||
@ -1283,12 +1384,120 @@ begin
|
||||
Params.Free;
|
||||
ClearIgnoreErrorAfter;
|
||||
DeactivateGlobalWriteLock;
|
||||
CurrentIdentifierList:=nil;
|
||||
end;
|
||||
{$IFDEF CTDEBUG}
|
||||
DebugLn('TIdentCompletionTool.GatherIdentifiers END');
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
function TIdentCompletionTool.FindCodeContext(const CursorPos: TCodeXYPosition;
|
||||
out CodeContexts: TCodeContextInfo): boolean;
|
||||
var
|
||||
CleanCursorPos: integer;
|
||||
CursorNode: TCodeTreeNode;
|
||||
Params: TFindDeclarationParams;
|
||||
|
||||
function CheckContextIsParameter(var Ok: boolean): boolean;
|
||||
// returns true, on error or context is parameter
|
||||
// returns false, if no error and context is not parameter
|
||||
var
|
||||
VarNameAtom, ProcNameAtom: TAtomPosition;
|
||||
ParameterIndex: integer;
|
||||
GatherContext: TFindContext;
|
||||
ContextExprStartPos: LongInt;
|
||||
StartInSubContext: Boolean;
|
||||
begin
|
||||
Result:=false;
|
||||
if (CursorNode.Desc<>ctnBeginBlock)
|
||||
and (not CursorNode.HasParentOfType(ctnBeginBlock)) then exit;
|
||||
//DebugLn('CheckContextIsParameter ');
|
||||
if not CheckParameterSyntax(CursorNode, CleanCursorPos,
|
||||
VarNameAtom, ProcNameAtom, ParameterIndex) then exit;
|
||||
if VarNameAtom.StartPos<1 then exit;
|
||||
//DebugLn('CheckContextIsParameter Variable=',GetAtom(VarNameAtom),' Proc=',GetAtom(ProcNameAtom),' ParameterIndex=',dbgs(ParameterIndex));
|
||||
|
||||
// it is a parameter -> save ParameterIndex
|
||||
Result:=true;
|
||||
if CurrentContexts=nil then
|
||||
CurrentContexts:=TCodeContextInfo.Create;
|
||||
CurrentContexts.ParameterIndex:=ParameterIndex+1;
|
||||
CurrentContexts.ProcName:=GetAtom(ProcNameAtom);
|
||||
MoveCursorToAtomPos(ProcNameAtom);
|
||||
ReadNextAtom; // read opening bracket
|
||||
CurrentContexts.StartPos:=CurPos.EndPos;
|
||||
// read closing bracket
|
||||
if ReadTilBracketClose(false) then
|
||||
CurrentContexts.EndPos:=CurPos.StartPos
|
||||
else
|
||||
CurrentContexts.EndPos:=SrcLen+1;
|
||||
|
||||
FindCollectionContext(Params,ProcNameAtom.StartPos,CursorNode,
|
||||
GatherContext,ContextExprStartPos,StartInSubContext);
|
||||
|
||||
// gather declarations of parameter lists
|
||||
Params.ContextNode:=GatherContext.Node;
|
||||
Params.SetIdentifier(Self,@Src[ProcNameAtom.StartPos],@CollectAllContexts);
|
||||
Params.Flags:=[fdfSearchInAncestors,fdfCollect,fdfFindVariable];
|
||||
if not StartInSubContext then
|
||||
Include(Params.Flags,fdfSearchInParentNodes);
|
||||
if Params.ContextNode.Desc in [ctnClass,ctnClassInterface] then
|
||||
Exclude(Params.Flags,fdfSearchInParentNodes);
|
||||
CurrentIdentifierList.Context:=GatherContext;
|
||||
//DebugLn('CheckContextIsParameter searching procedure ...');
|
||||
GatherContext.Tool.FindIdentifierInContext(Params);
|
||||
//DebugLn('CheckContextIsParameter END');
|
||||
Ok:=true;
|
||||
end;
|
||||
|
||||
var
|
||||
IdentifierList: TIdentifierList;
|
||||
IdentStartPos, IdentEndPos: integer;
|
||||
begin
|
||||
CodeContexts:=nil;
|
||||
Result:=false;
|
||||
|
||||
IdentifierList:=nil;
|
||||
CurrentContexts:=CodeContexts;
|
||||
|
||||
ActivateGlobalWriteLock;
|
||||
Params:=TFindDeclarationParams.Create;
|
||||
try
|
||||
InitCollectIdentifiers(CursorPos,IdentifierList);
|
||||
ParseSourceTillCollectionStart(CursorPos,CleanCursorPos,CursorNode,
|
||||
IdentStartPos,IdentEndPos);
|
||||
|
||||
// find class and ancestors if existing (needed for protected identifiers)
|
||||
FindContextClassAndAncestors(CursorPos,ClassAndAncestors);
|
||||
|
||||
if CursorNode<>nil then begin
|
||||
if CheckContextIsParameter(Result) then exit;
|
||||
end;
|
||||
|
||||
if CodeContexts=nil then begin
|
||||
// create default
|
||||
AddCollectionContext(Self,CursorNode);
|
||||
end;
|
||||
|
||||
Result:=true;
|
||||
finally
|
||||
if Result then begin
|
||||
CodeContexts:=CurrentContexts;
|
||||
CurrentContexts:=nil;
|
||||
end else begin
|
||||
FreeAndNil(CurrentContexts);
|
||||
end;
|
||||
FreeListOfPFindContext(ClassAndAncestors);
|
||||
FreeAndNil(FoundPublicProperties);
|
||||
Params.Free;
|
||||
ClearIgnoreErrorAfter;
|
||||
DeactivateGlobalWriteLock;
|
||||
FreeAndNil(CurrentIdentifierList);
|
||||
end;
|
||||
Result:=false;
|
||||
end;
|
||||
|
||||
|
||||
{ TIdentifierListItem }
|
||||
|
||||
function TIdentifierListItem.GetParamList: string;
|
||||
@ -1553,6 +1762,43 @@ begin
|
||||
Result:=FItems.Count;
|
||||
end;
|
||||
|
||||
{ TCodeContextInfo }
|
||||
|
||||
function TCodeContextInfo.GetItems(Index: integer): TExpressionType;
|
||||
begin
|
||||
Result:=FItems[Index];
|
||||
end;
|
||||
|
||||
constructor TCodeContextInfo.Create;
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
destructor TCodeContextInfo.Destroy;
|
||||
begin
|
||||
Clear;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TCodeContextInfo.Count: integer;
|
||||
begin
|
||||
Result:=FCount;
|
||||
end;
|
||||
|
||||
function TCodeContextInfo.Add(const Context: TExpressionType): integer;
|
||||
begin
|
||||
inc(FCount);
|
||||
Result:=Count;
|
||||
ReAllocMem(FItems,SizeOf(TExpressionType)*FCount);
|
||||
FItems[FCount-1]:=Context;
|
||||
end;
|
||||
|
||||
procedure TCodeContextInfo.Clear;
|
||||
begin
|
||||
FCount:=0;
|
||||
ReAllocMem(FItems,0);
|
||||
end;
|
||||
|
||||
initialization
|
||||
IdentifierListItemMemManager:=TIdentifierListItemMemManager.Create;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user