mirror of
				https://gitlab.com/freepascal.org/lazarus/lazarus.git
				synced 2025-10-31 14:21:31 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			257 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			257 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| {
 | |
|  ***************************************************************************
 | |
|  *                                                                         *
 | |
|  *   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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA.   *
 | |
|  *                                                                         *
 | |
|  ***************************************************************************
 | |
| 
 | |
|   Author: Mattias Gaertner
 | |
| 
 | |
|   Abstract:
 | |
|     High level caches.
 | |
| }
 | |
| unit CacheCodeTools;
 | |
| 
 | |
| {$mode objfpc}{$H+}
 | |
| 
 | |
| interface
 | |
| 
 | |
| uses
 | |
|   Classes, SysUtils, Laz_AVL_Tree,
 | |
|   // Codetools
 | |
|   FileProcs, CodeCache, KeywordFuncLists, CustomCodeTool,
 | |
|   BasicCodeTools, FindDeclarationTool;
 | |
| 
 | |
| type
 | |
| 
 | |
|   { TDeclarationInheritanceCacheItem }
 | |
| 
 | |
|   TDeclarationInheritanceCacheItem = class
 | |
|   public
 | |
|     CodePos: TCodePosition;
 | |
|     ListOfPCodeXYPosition: TFPList;
 | |
|     destructor Destroy; override;
 | |
|   end;
 | |
| 
 | |
|   { TDeclarationInheritanceCacheTree
 | |
|     Tree of TDeclarationInheritanceCacheItem sorted by CompareDeclInhCacheItems }
 | |
| 
 | |
|   TDeclarationInheritanceCacheTree = class(TAVLTree)
 | |
|   public
 | |
|     CodeToolsChangeStep: integer;
 | |
|     constructor CreateDeclInhTree;
 | |
|     destructor Destroy; override;
 | |
|   end;
 | |
|   
 | |
|   TOnFindDeclarations = function(Code: TCodeBuffer; X,Y: integer;
 | |
|           out ListOfPCodeXYPosition: TFPList;
 | |
|           Flags: TFindDeclarationListFlags): boolean of object;
 | |
| 
 | |
|   TDeclarationInheritanceCache = class
 | |
|   private
 | |
|     FCurrent: TDeclarationInheritanceCacheTree;
 | |
|     FOldTrees: TFPList; // list of TDeclarationInheritanceCacheTree
 | |
|     FOnFindDeclarations: TOnFindDeclarations;
 | |
|     FOnGetNodesDeletedStep: TGetChangeStepEvent;
 | |
|     procedure CheckCurrentIsValid;
 | |
|     procedure CleanCache(FreeItemCount: integer);
 | |
|   public
 | |
|     constructor Create(const TheOnFindDeclarations: TOnFindDeclarations;
 | |
|                        const TheOnGetNodesDeletedStep: TGetChangeStepEvent);
 | |
|     destructor Destroy; override;
 | |
|     procedure Clear;
 | |
|     function FindDeclarations(Code: TCodeBuffer; X,Y: integer;
 | |
|           out ListOfPCodeXYPosition: TFPList;
 | |
|           out CacheWasUsed: boolean): boolean;
 | |
|     property OnFindDeclarations: TOnFindDeclarations read FOnFindDeclarations
 | |
|                                                      write FOnFindDeclarations;
 | |
|     property OnGetNodesDeletedStep: TGetChangeStepEvent read FOnGetNodesDeletedStep
 | |
|                                                    write FOnGetNodesDeletedStep;
 | |
|   end;
 | |
| 
 | |
| function CompareDeclInhCacheItems(Data1, Data2: Pointer): integer;
 | |
| function ComparePCodePosWithDeclInhCacheItem(CodePosition, DeclInhItem: Pointer): integer;
 | |
| 
 | |
| implementation
 | |
| 
 | |
| function CompareDeclInhCacheItems(Data1, Data2: Pointer): integer;
 | |
| var
 | |
|   Item1: TDeclarationInheritanceCacheItem;
 | |
|   Item2: TDeclarationInheritanceCacheItem;
 | |
| begin
 | |
|   Item1:=TDeclarationInheritanceCacheItem(Data1);
 | |
|   Item2:=TDeclarationInheritanceCacheItem(Data2);
 | |
|   Result:=CompareCodePositions(@Item1.CodePos,@Item2.CodePos);
 | |
| end;
 | |
| 
 | |
| function ComparePCodePosWithDeclInhCacheItem(CodePosition, DeclInhItem: Pointer): integer;
 | |
| begin
 | |
|   Result:=CompareCodePositions(PCodePosition(CodePosition),
 | |
|                                @TDeclarationInheritanceCacheItem(DeclInhItem).CodePos);
 | |
| end;
 | |
| 
 | |
| procedure TDeclarationInheritanceCache.CheckCurrentIsValid;
 | |
| var
 | |
|   NodesDeletedStep: integer;
 | |
| begin
 | |
|   if FCurrent=nil then exit;
 | |
|   OnGetNodesDeletedStep(NodesDeletedStep);
 | |
|   if (FCurrent.CodeToolsChangeStep=NodesDeletedStep) then exit;
 | |
|   // the current cache is invalid => move to old
 | |
|   if FOldTrees=nil then FOldTrees:=TFPList.Create;
 | |
|   FOldTrees.Add(FCurrent);
 | |
|   FCurrent:=nil;
 | |
| end;
 | |
| 
 | |
| procedure TDeclarationInheritanceCache.CleanCache(FreeItemCount: integer);
 | |
| // free some old cache items
 | |
| var
 | |
|   i: Integer;
 | |
|   OldTree: TDeclarationInheritanceCacheTree;
 | |
| begin
 | |
|   for i:=1 to FreeItemCount do begin
 | |
|     if FOldTrees=nil then exit;
 | |
|     if FOldTrees.Count=0 then begin
 | |
|       FreeAndNil(FOldTrees);
 | |
|     end else begin
 | |
|       OldTree:=TDeclarationInheritanceCacheTree(FOldTrees[FOldTrees.Count-1]);
 | |
|       if OldTree.Count=0 then begin
 | |
|         OldTree.Free;
 | |
|         FOldTrees.Delete(FOldTrees.Count-1);
 | |
|       end else begin
 | |
|         OldTree.FreeAndDelete(OldTree.Root);
 | |
|       end;
 | |
|     end;
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| constructor TDeclarationInheritanceCache.Create(
 | |
|   const TheOnFindDeclarations: TOnFindDeclarations;
 | |
|   const TheOnGetNodesDeletedStep: TGetChangeStepEvent);
 | |
| begin
 | |
|   OnFindDeclarations:=TheOnFindDeclarations;
 | |
|   OnGetNodesDeletedStep:=TheOnGetNodesDeletedStep;
 | |
| end;
 | |
| 
 | |
| destructor TDeclarationInheritanceCache.Destroy;
 | |
| begin
 | |
|   Clear;
 | |
|   FreeAndNil(FCurrent);
 | |
|   FreeAndNil(FOldTrees);
 | |
|   inherited Destroy;
 | |
| end;
 | |
| 
 | |
| procedure TDeclarationInheritanceCache.Clear;
 | |
| var
 | |
|   i: LongInt;
 | |
| begin
 | |
|   if FOldTrees<>nil then begin
 | |
|     for i:=FOldTrees.Count-1 downto 0 do
 | |
|       TDeclarationInheritanceCacheTree(FOldTrees[i]).Free;
 | |
|     FreeAndNil(FOldTrees);
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| function TDeclarationInheritanceCache.FindDeclarations(Code: TCodeBuffer; X,
 | |
|   Y: integer; out ListOfPCodeXYPosition: TFPList; out CacheWasUsed: boolean
 | |
|   ): boolean;
 | |
| var
 | |
|   CodePos: TCodePosition;
 | |
|   AVLNode: TAVLTreeNode;
 | |
|   Item: TDeclarationInheritanceCacheItem;
 | |
| begin
 | |
|   Result:=false;
 | |
|   ListOfPCodeXYPosition:=nil;
 | |
|   CacheWasUsed:=true;
 | |
|   if Code=nil then exit;
 | |
|   CodePos.Code:=Code;
 | |
|   Code.LineColToPosition(Y,X,CodePos.P);
 | |
|   if (CodePos.P<1) or (CodePos.P>Code.SourceLength) then exit;
 | |
| 
 | |
|   // move cursor to start of atom (needed to find CodePos in cache)
 | |
|   CodePos.P:=FindStartOfAtom(Code.Source,CodePos.P);
 | |
| 
 | |
|   // search in cache
 | |
|   CheckCurrentIsValid;
 | |
|   if FCurrent<>nil then begin
 | |
|     // the current cache is valid
 | |
|     AVLNode:=FCurrent.FindKey(@CodePos,@ComparePCodePosWithDeclInhCacheItem);
 | |
|     if AVLNode<>nil then begin
 | |
|       Item:=TDeclarationInheritanceCacheItem(AVLNode.Data);
 | |
|       ListOfPCodeXYPosition:=Item.ListOfPCodeXYPosition;
 | |
|       Result:=ListOfPCodeXYPosition<>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
 | |
|     Result:=true;
 | |
|   end else begin
 | |
|     FreeAndNil(ListOfPCodeXYPosition);
 | |
|     Result:=false;
 | |
|   end;
 | |
| 
 | |
|   // save to cache
 | |
|   Item:=TDeclarationInheritanceCacheItem.Create;
 | |
|   Item.CodePos:=CodePos;
 | |
|   Item.ListOfPCodeXYPosition:=ListOfPCodeXYPosition;
 | |
|   CheckCurrentIsValid;
 | |
|   if FCurrent=nil then begin
 | |
|     FCurrent:=TDeclarationInheritanceCacheTree.CreateDeclInhTree;
 | |
|     OnGetNodesDeletedStep(FCurrent.CodeToolsChangeStep);
 | |
|   end;
 | |
|   FCurrent.Add(Item);
 | |
|   
 | |
|   //if ListOfPCodeXYPosition<>nil then DebugLn(['TDeclarationInheritanceCache.FindDeclarations ',ListOfPCodeXYPositionToStr(ListOfPCodeXYPosition)]);
 | |
| 
 | |
|   // clean up cache a bit
 | |
|   CleanCache(5);
 | |
|   
 | |
|   // consistency check
 | |
|   AVLNode:=FCurrent.FindKey(@CodePos,@ComparePCodePosWithDeclInhCacheItem);
 | |
|   if Item<>TDeclarationInheritanceCacheItem(AVLNode.Data) then raise Exception.Create('');
 | |
| end;
 | |
| 
 | |
| constructor TDeclarationInheritanceCacheTree.CreateDeclInhTree;
 | |
| begin
 | |
|   Create(@CompareDeclInhCacheItems);
 | |
| end;
 | |
| 
 | |
| destructor TDeclarationInheritanceCacheTree.Destroy;
 | |
| begin
 | |
|   FreeAndClear;
 | |
|   inherited Destroy;
 | |
| end;
 | |
| 
 | |
| { TDeclarationInheritanceCacheItem }
 | |
| 
 | |
| destructor TDeclarationInheritanceCacheItem.Destroy;
 | |
| begin
 | |
|   FreeListOfPCodeXYPosition(ListOfPCodeXYPosition);
 | |
|   ListOfPCodeXYPosition:=nil;
 | |
|   inherited Destroy;
 | |
| end;
 | |
| 
 | |
| end.
 | |
| 
 | 
