IDE: lazdoc: implemented TLazDocManager.GetElementChain

git-svn-id: trunk@12959 -
This commit is contained in:
mattias 2007-11-21 22:18:22 +00:00
parent 6c50e20fca
commit 0c5ee1ee92
5 changed files with 317 additions and 37 deletions

View File

@ -40,7 +40,7 @@ type
TDeclarationInheritanceCacheItem = class
public
CodePos: TCodePosition;
ListOfPCodeXYPosition: TFPList;
ListOfPFindContext: TFPList;
destructor Destroy; override;
end;
@ -55,7 +55,7 @@ type
end;
TOnFindDeclarations = function(Code: TCodeBuffer; X,Y: integer;
var ListOfPCodeXYPosition: TFPList;
out ListOfPFindContext: TFPList;
Flags: TFindDeclarationListFlags): boolean of object;
TDeclarationInheritanceCache = class
@ -70,7 +70,7 @@ type
destructor Destroy; override;
procedure Clear;
function FindDeclarations(Code: TCodeBuffer; X,Y: integer;
out ListOfPCodeXYPosition: TFPList;
out ListOfPFindContext: TFPList;
out CacheWasUsed: boolean): boolean;
property OnFindDeclarations: TOnFindDeclarations read FOnFindDeclarations
write FOnFindDeclarations;
@ -156,7 +156,7 @@ begin
end;
function TDeclarationInheritanceCache.FindDeclarations(Code: TCodeBuffer; X,
Y: integer; out ListOfPCodeXYPosition: TFPList; out CacheWasUsed: boolean
Y: integer; out ListOfPFindContext: TFPList; out CacheWasUsed: boolean
): boolean;
var
CodePos: TCodePosition;
@ -164,7 +164,7 @@ var
Item: TDeclarationInheritanceCacheItem;
begin
Result:=false;
ListOfPCodeXYPosition:=nil;
ListOfPFindContext:=nil;
CacheWasUsed:=true;
if Code=nil then exit;
CodePos.Code:=Code;
@ -183,28 +183,30 @@ begin
AVLNode:=FCurrent.FindKey(@CodePos,@ComparePCodePosWithDeclInhCacheItem);
if AVLNode<>nil then begin
Item:=TDeclarationInheritanceCacheItem(AVLNode.Data);
ListOfPCodeXYPosition:=Item.ListOfPCodeXYPosition;
Result:=ListOfPCodeXYPosition<>nil;
ListOfPFindContext:=Item.ListOfPFindContext;
Result:=ListOfPFindContext<>nil;
exit;
end;
end;
CacheWasUsed:=false;
DebugLn(['TDeclarationInheritanceCache.FindDeclarations searching ',Code.Filename,'(X=',X,',Y=',Y,')']);
// ask the codetools
if OnFindDeclarations(Code,X,Y,ListOfPCodeXYPosition,[])
and (ListOfPCodeXYPosition<>nil)
and (ListOfPCodeXYPosition.Count>0) then begin
if OnFindDeclarations(Code,X,Y,ListOfPFindContext,[])
and (ListOfPFindContext<>nil)
and (ListOfPFindContext.Count>0) then begin
Result:=true;
end else begin
FreeAndNil(ListOfPCodeXYPosition);
FreeAndNil(ListOfPFindContext);
Result:=false;
end;
// save to cache
Item:=TDeclarationInheritanceCacheItem.Create;
Item.CodePos:=CodePos;
Item.ListOfPCodeXYPosition:=ListOfPCodeXYPosition;
Item.ListOfPFindContext:=ListOfPFindContext;
CheckCurrentIsValid;
if FCurrent=nil then begin
FCurrent:=TDeclarationInheritanceCacheTree.CreateDeclInhTree;
@ -231,8 +233,8 @@ end;
destructor TDeclarationInheritanceCacheItem.Destroy;
begin
FreeListOfPCodeXYPosition(ListOfPCodeXYPosition);
ListOfPCodeXYPosition:=nil;
FreeListOfPFindContext(ListOfPFindContext);
ListOfPFindContext:=nil;
inherited Destroy;
end;

View File

@ -360,7 +360,10 @@ type
out NewCode: TCodeBuffer;
out NewX, NewY, NewTopLine: integer): Boolean;
function FindDeclarationAndOverload(Code: TCodeBuffer; X,Y: integer;
var ListOfPCodeXYPosition: TFPList;
out ListOfPCodeXYPosition: TFPList;
Flags: TFindDeclarationListFlags): boolean;
function FindDeclarationNodeAndOverload(Code: TCodeBuffer; X,Y: integer;
out ListOfPFindContext: TFPList;
Flags: TFindDeclarationListFlags): boolean;
function FindMainDeclaration(Code: TCodeBuffer; X,Y: integer;
out NewCode: TCodeBuffer;
@ -1749,7 +1752,7 @@ begin
end;
function TCodeToolManager.FindDeclarationAndOverload(Code: TCodeBuffer; X,
Y: integer; var ListOfPCodeXYPosition: TFPList;
Y: integer; out ListOfPCodeXYPosition: TFPList;
Flags: TFindDeclarationListFlags): boolean;
var
CursorPos: TCodeXYPosition;
@ -1767,7 +1770,7 @@ begin
{$ENDIF}
try
Result:=FCurCodeTool.FindDeclarationAndOverload(CursorPos,
ListOfPCodeXYPosition,Flags);
ListOfPCodeXYPosition,Flags);
except
on e: Exception do Result:=HandleException(e);
end;
@ -1776,6 +1779,34 @@ begin
{$ENDIF}
end;
function TCodeToolManager.FindDeclarationNodeAndOverload(Code: TCodeBuffer; X,
Y: integer; out ListOfPFindContext: TFPList; Flags: TFindDeclarationListFlags
): boolean;
var
CursorPos: TCodeXYPosition;
begin
Result:=false;
{$IFDEF CTDEBUG}
DebugLn('TCodeToolManager.FindDeclarationNodeAndOverload A ',Code.Filename,' x=',dbgs(x),' y=',dbgs(y));
{$ENDIF}
if not InitCurCodeTool(Code) then exit;
CursorPos.X:=X;
CursorPos.Y:=Y;
CursorPos.Code:=Code;
{$IFDEF CTDEBUG}
DebugLn('TCodeToolManager.FindDeclarationNodeAndOverload B ',dbgs(FCurCodeTool.Scanner<>nil));
{$ENDIF}
try
Result:=FCurCodeTool.FindDeclarationNodeAndOverload(CursorPos,
ListOfPFindContext,Flags);
except
on e: Exception do Result:=HandleException(e);
end;
{$IFDEF CTDEBUG}
DebugLn('TCodeToolManager.FindDeclarationNodeAndOverload END ');
{$ENDIF}
end;
function TCodeToolManager.FindMainDeclaration(Code: TCodeBuffer; X, Y: integer;
out NewCode: TCodeBuffer; out NewX, NewY, NewTopLine: integer): boolean;
var

View File

@ -732,6 +732,9 @@ type
function FindDeclarationAndOverload(const CursorPos: TCodeXYPosition;
out ListOfPCodeXYPosition: TFPList;
Flags: TFindDeclarationListFlags): boolean;
function FindDeclarationNodeAndOverload(const CursorPos: TCodeXYPosition;
out ListOfPFindContext: TFPList;
Flags: TFindDeclarationListFlags): boolean;
function FindClassAndAncestors(ClassNode: TCodeTreeNode;
out ListOfPFindContext: TFPList): boolean;
function FindContextClassAndAncestors(const CursorPos: TCodeXYPosition;
@ -3368,9 +3371,93 @@ begin
on E: ELinkScannerError do ;
end;
finally
DeactivateGlobalWriteLock;
FreeListOfPCodeXYPosition(OldPositions);
NodeList.Free;
DeactivateGlobalWriteLock;
end;
end;
function TFindDeclarationTool.FindDeclarationNodeAndOverload(
const CursorPos: TCodeXYPosition; out ListOfPFindContext: TFPList;
Flags: TFindDeclarationListFlags): boolean;
var
NewContext: TFindContext;
OldPositions: TFPList;
NodeList: TFPList;
procedure AddPos;
begin
AddFindContext(OldPositions,NewContext);
if (NodeList.IndexOf(NewContext.Node)>=0) then
exit;
NodeList.Add(NewContext.Node);
if (fdlfWithoutEmptyProperties in Flags)
and (NewContext.Node.Desc=ctnProperty)
and (NewContext.Tool.PropNodeIsTypeLess(NewContext.Node)) then
exit;
if (fdlfWithoutForwards in Flags) then begin
if (NewContext.Node.Desc in [ctnTypeDefinition,ctnGenericType])
and NewContext.Tool.NodeIsForwardDeclaration(NewContext.Node)
then
exit;
if (NewContext.Node.Desc=ctnProcedure)
and ((NewContext.Node.SubDesc and ctnsForwardDeclaration)>0) then
exit;
end;
AddFindContext(ListOfPFindContext,NewContext);
end;
var
CurCursorPos: TCodeXYPosition;
CurTool: TFindDeclarationTool;
NewPos: TCodeXYPosition;
NewTopLine: integer;
CleanPos: integer;
begin
Result:=true;
ListOfPFindContext:=nil;
NewContext:=CleanFindContext;
OldPositions:=nil;
NodeList:=nil;
ActivateGlobalWriteLock;
try
BuildTreeAndGetCleanPos(trAll,CursorPos,CleanPos,[]);
NodeList:=TFPList.Create;
NewContext.Tool:=Self;
NewContext.Node:=FindDeepestExpandedNodeAtPos(CleanPos,true);
AddPos;
CurCursorPos:=CursorPos;
CurTool:=Self;
try
while CurTool.FindDeclaration(CurCursorPos,AllFindSmartFlags
+[fsfSearchSourceName],
NewContext.Tool,NewContext.Node,NewPos,NewTopLine) do
begin
if IndexOfFindContext(OldPositions,@NewContext)>=0 then break;
AddPos;
CurCursorPos:=NewPos;
CurTool:=NewContext.Tool;
debugln('TFindDeclarationTool.FindDeclarationAndOverload ',
' Self="',MainFilename,'" ');
if CurCursorPos.Code<>nil then
debugln(' CurCursorPos=',CurCursorPos.Code.Filename,' ',dbgs(CurCursorPos.X),',',dbgs(CurCursorPos.Y));
if CurTool<>nil then
debugln(' CurTool=',CurTool.MainFilename);
if (CurTool=nil) then exit;
end;
except
// ignore normal errors
on E: ECodeToolError do ;
on E: ELinkScannerError do ;
end;
finally
FreeListOfPFindContext(OldPositions);
NodeList.Free;
DeactivateGlobalWriteLock;
end;
end;

View File

@ -32,7 +32,7 @@ interface
uses
Classes, SysUtils, LCLProc, FileUtil,
CodeAtom, CodeTree, CodeToolManager, CodeCache, CacheCodeTools,
CodeAtom, CodeTree, CodeToolManager, FindDeclarationTool, CodeCache, CacheCodeTools,
FileProcs, AvgLvlTree,
Laz_DOM, Laz_XMLRead, Laz_XMLWrite,
MacroIntf, PackageIntf, LazHelpIntf, ProjectIntf, LazIDEIntf,
@ -62,6 +62,35 @@ type
FPDocFilenameTimeStamp: integer;
end;
{ TLazDocElement }
TLazDocElement = class
public
CodeContext: TFindContext;
ElementName: string;
ElementNode: TDOMNode;
FPDocFile: TLazFPDocFile;
end;
{ TLazDocElementChain }
TLazDocElementChain = class
private
FItems: TFPList; // list of TLazDocElement
function GetCount: integer;
function GetItems(Index: integer): TLazDocElement;
function Add: TLazDocElement;
public
CodePos: TCodePosition;
IDEChangeStep: integer;
CodetoolsChangeStep: integer;
constructor Create;
destructor Destroy; override;
procedure Clear;
property Items[Index: integer]: TLazDocElement read GetItems; default;
property Count: integer read GetCount;
end;
TLazDocChangeEvent =
procedure(Sender: TObject; LazDocFPFile: TLazFPDocFile) of object;
@ -71,11 +100,11 @@ type
);
TLazDocParseResult = (
ldprParsing, // not yet completed
ldprParsing, // means: done a small step, but not yet finished the job
ldprFailed,
ldprSuccess
);
{ TLazDocManager }
TLazDocManager = class
@ -107,13 +136,17 @@ type
function GetFPDocFilenameForSource(SrcFilename: string;
ResolveIncludeFiles: Boolean;
out CacheWasUsed: boolean): string;
function CodeNodeToElementName(Tool: TCodeTool; CodeNode: TCodeTreeNode): string;
function CodeNodeToElementName(Tool: TFindDeclarationTool;
CodeNode: TCodeTreeNode): string;
function GetFPDocNode(Tool: TCodeTool; CodeNode: TCodeTreeNode; Complete: boolean;
out FPDocFile: TLazFPDocFile; out DOMNode: TDOMNode;
out CacheWasUsed: boolean): TLazDocParseResult;
function GetDeclarationChain(Code: TCodeBuffer; X, Y: integer;
out ListOfPCodeXYPosition: TFPList;
out ListOfPFindContext: TFPList;
out CacheWasUsed: boolean): TLazDocParseResult;
function GetElementChain(Code: TCodeBuffer; X, Y: integer; Complete: boolean;
out Chain: TLazDocElementChain;
out CacheWasUsed: boolean): TLazDocParseResult;
public
// Event lists
procedure RemoveAllHandlersOfObject(AnObject: TObject);
@ -239,7 +272,7 @@ begin
FDocs:=TAvgLvlTree.Create(@CompareLazFPDocFilenames);
FSrcToDocMap:=TAvgLvlTree.Create(@CompareLDSrc2DocSrcFilenames);
FDeclarationCache:=TDeclarationInheritanceCache.Create(
@CodeToolBoss.FindDeclarationAndOverload);
@CodeToolBoss.FindDeclarationNodeAndOverload);
end;
destructor TLazDocManager.Destroy;
@ -426,6 +459,8 @@ begin
end;
end;
CacheWasUsed:=false;
DebugLn(['TLazDocManager.GetFPDocFilenameForSource searching SrcFilename=',SrcFilename]);
// first check if the file is owned by any project/package
SearchPath:='';
@ -449,7 +484,7 @@ begin
MapEntry.FPDocFilenameTimeStamp:=CompilerParseStamp;
end;
function TLazDocManager.CodeNodeToElementName(Tool: TCodeTool;
function TLazDocManager.CodeNodeToElementName(Tool: TFindDeclarationTool;
CodeNode: TCodeTreeNode): string;
var
NodeName: String;
@ -507,10 +542,10 @@ begin
end;
function TLazDocManager.GetDeclarationChain(Code: TCodeBuffer; X, Y: integer;
out ListOfPCodeXYPosition: TFPList; out CacheWasUsed: boolean
out ListOfPFindContext: TFPList; out CacheWasUsed: boolean
): TLazDocParseResult;
begin
if FDeclarationCache.FindDeclarations(Code,X,Y,ListOfPCodeXYPosition,
if FDeclarationCache.FindDeclarations(Code,X,Y,ListOfPFindContext,
CacheWasUsed)
then
Result:=ldprSuccess
@ -518,6 +553,77 @@ begin
Result:=ldprFailed;
end;
function TLazDocManager.GetElementChain(Code: TCodeBuffer; X, Y: integer;
Complete: boolean; out Chain: TLazDocElementChain; out CacheWasUsed: boolean
): TLazDocParseResult;
var
ListOfPFindContext: TFPList;
i: Integer;
CodeContext: PFindContext;
LDElement: TLazDocElement;
SrcFilename: String;
FPDocFilename: String;
begin
Chain:=nil;
ListOfPFindContext:=nil;
try
DebugLn(['TLazDocManager.GetElementChain GetDeclarationChain...']);
// get the declaration chain
Result:=GetDeclarationChain(Code,X,Y,ListOfPFindContext,CacheWasUsed);
if Result<>ldprSuccess then exit;
if (not CacheWasUsed) and (not Complete) then exit(ldprParsing);
DebugLn(['TLazDocManager.GetElementChain init the element chain: ListOfPFindContext.Count=',ListOfPFindContext.Count,' ...']);
// init the element chain
Result:=ldprParsing;
Chain:=TLazDocElementChain.Create;
Chain.CodePos.Code:=Code;
Code.LineColToPosition(Y,X,Chain.CodePos.P);
// fill the element chain
for i:=0 to ListOfPFindContext.Count-1 do begin
LDElement:=Chain.Add;
// get source position of declaration
CodeContext:=PFindContext(ListOfPFindContext[i]);
LDElement.CodeContext:=CodeContext^;
DebugLn(['TLazDocManager.GetElementChain i=',i,' CodeContext=',FindContextToString(LDElement.CodeContext)]);
// find corresponding FPDoc file
SrcFilename:=LDElement.CodeContext.Tool.MainFilename;
FPDocFilename:=GetFPDocFilenameForSource(SrcFilename,false,CacheWasUsed);
DebugLn(['TLazDocManager.GetElementChain FPDocFilename=',FPDocFilename]);
if (not CacheWasUsed) and (not Complete) then exit(ldprParsing);
if FPDocFilename<>'' then begin
// load FPDoc file
LoadFPDocFile(FPDocFilename,true,false,LDElement.FPDocFile,
CacheWasUsed);
if (not CacheWasUsed) and (not Complete) then exit(ldprParsing);
end;
end;
// get fpdoc nodes
for i:=0 to Chain.Count-1 do begin
LDElement:=Chain[i];
// get fpdoc element path
LDElement.ElementName:=CodeNodeToElementName(LDElement.CodeContext.Tool,
LDElement.CodeContext.Node);
DebugLn(['TLazDocManager.GetElementChain i=',i,' Element=',LDElement.ElementName]);
// get fpdoc node
if (LDElement.FPDocFile<>nil) and (LDElement.ElementName<>'') then begin
LDElement.ElementNode:=
LDElement.FPDocFile.GetElementWithName(LDElement.ElementName);
end;
DebugLn(['TLazDocManager.GetElementChain ElementNode=',LDElement.ElementNode<>nil]);
end;
Result:=ldprSuccess;
finally
FreeListOfPFindContext(ListOfPFindContext);
if Result<>ldprSuccess then
FreeAndNil(Chain);
end;
end;
procedure TLazDocManager.FreeDocs;
var
AVLNode: TAvgLvlTreeNode;
@ -568,5 +674,42 @@ begin
end;
{ TLazDocElementChain }
function TLazDocElementChain.GetCount: integer;
begin
Result:=FItems.Count;
end;
function TLazDocElementChain.GetItems(Index: integer): TLazDocElement;
begin
Result:=TLazDocElement(FItems[Index]);
end;
function TLazDocElementChain.Add: TLazDocElement;
begin
Result:=TLazDocElement.Create;
FItems.Add(Result);
end;
constructor TLazDocElementChain.Create;
begin
FItems:=TFPList.Create;
end;
destructor TLazDocElementChain.Destroy;
begin
Clear;
inherited Destroy;
end;
procedure TLazDocElementChain.Clear;
var
i: Integer;
begin
for i:=0 to FItems.Count-1 do TObject(FItems[i]).Free;
FItems.Clear;
end;
end.

View File

@ -89,8 +89,9 @@ var
Position: LongInt;
Item: TIdentifierListItem;
Code: TCodeBuffer;
DocFilename: String;
UsedCache: boolean;
CacheWasUsed: boolean;
Chain: TLazDocElementChain;
Y,X: integer;
begin
if (SourceEditorWindow=nil) or (CodeToolBoss=nil)
or (CodeToolBoss.IdentifierList=nil) then
@ -100,15 +101,31 @@ begin
exit;
Item:=CodeToolBoss.IdentifierList.FilteredItems[Position];
DebugLn(['TLazDocHintProvider.ReadLazDocData Identifier=',GetIdentifier(Item.Identifier)]);
if (Item.Node<>nil) then begin
if (Item.Tool.Scanner=nil) then exit;
Code:=TCodeBuffer(Item.Tool.Scanner.MainCode);
if Code=nil then exit;
DocFilename:=LazDocBoss.GetFPDocFilenameForSource(Code.Filename,false,UsedCache);
if DocFilename='' then exit;
DebugLn(['TLazDocHintProvider.ReadLazDocData DocFilename=',DocFilename]);
end else begin
Chain:=nil;
try
if (Item.Node<>nil) then begin
if (Item.Tool.Scanner=nil) then exit;
Code:=TCodeBuffer(Item.Tool.Scanner.MainCode);
if Code=nil then begin
DebugLn(['TLazDocHintProvider.ReadLazDocData FAILED Tool without MainCode']);
exit;
end;
Code.AbsoluteToLineCol(Item.Node.StartPos,Y,X);
if (Y<1) or (X<1) then begin
DebugLn(['TLazDocHintProvider.ReadLazDocData FAILED X=',X,' Y=',Y]);
exit;
end;
LazDocBoss.GetElementChain(Code,X,Y,true,Chain,CacheWasUsed);
DebugLn(['TLazDocHintProvider.ReadLazDocData Chain=',Chain<>nil]);
if Chain=nil then begin
DebugLn(['TLazDocHintProvider.ReadLazDocData FAILED Chain=nil']);
exit;
end;
end else begin
end;
finally
Chain.Free;
end;
end;