diff --git a/.gitattributes b/.gitattributes index 235cf115ec..39b752b173 100644 --- a/.gitattributes +++ b/.gitattributes @@ -59,6 +59,7 @@ components/chmhelp/packages/idehelp/chmhelppkg.pas svneol=native#text/plain components/chmhelp/packages/idehelp/lazchmhelp.pas svneol=native#text/plain components/codetools/allcodetoolunits.pp svneol=native#text/pascal components/codetools/basiccodetools.pas svneol=native#text/pascal +components/codetools/cachecodetools.pas svneol=native#text/plain components/codetools/codeatom.pas svneol=native#text/pascal components/codetools/codebeautifier.pas svneol=native#text/plain components/codetools/codecache.pas svneol=native#text/pascal diff --git a/components/codetools/allcodetoolunits.pp b/components/codetools/allcodetoolunits.pp index 84c9be20ff..dae0830dd2 100644 --- a/components/codetools/allcodetoolunits.pp +++ b/components/codetools/allcodetoolunits.pp @@ -23,11 +23,10 @@ uses CodeTree, CodeAtom, SourceChanger, CodeToolMemManager, CodeCache, KeywordFuncLists, SourceLog, ExprEval, DefineTemplates, FileProcs, CodeToolsStrConsts, DirectoryCacher, - MultiKeyWordListTool, ResourceCodeTool, CodeToolsStructs, + MultiKeyWordListTool, ResourceCodeTool, CodeToolsStructs, CacheCodeTools, // fast xml units, changes not merged in current fpc Laz_DOM, Laz_XMLCfg, Laz_XMLRead, Laz_XMLWrite, Laz_XMLStreaming; - implementation end. diff --git a/components/codetools/cachecodetools.pas b/components/codetools/cachecodetools.pas new file mode 100644 index 0000000000..ee77885988 --- /dev/null +++ b/components/codetools/cachecodetools.pas @@ -0,0 +1,240 @@ +{ + *************************************************************************** + * * + * 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 . 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: + High level caches. +} +unit CacheCodeTools; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, + CodeAtom, CodeCache, KeywordFuncLists, CustomCodeTool, FindDeclarationTool, AVL_Tree; + +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; + var ListOfPCodeXYPosition: TFPList; + Flags: TFindDeclarationListFlags): boolean of object; + + TDeclarationInheritanceCache = class + private + FCurrent: TDeclarationInheritanceCacheTree; + FOldTrees: TFPList; // list of TDeclarationInheritanceCacheTree + FOnFindDeclarations: TOnFindDeclarations; + procedure CheckCurrentIsValid; + procedure CleanCache(FreeItemCount: integer); + public + constructor Create(const TheOnFindDeclarations: TOnFindDeclarations); + 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; + 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; +begin + if (FCurrent<>nil) + and (FCurrent.CodeToolsChangeStep<>GlobalCodeNodeTreeChangeStep) then begin + // the current cache is invalid => move to old + if FOldTrees=nil then FOldTrees:=TFPList.Create; + FOldTrees.Add(FCurrent); + FCurrent:=nil; + end; +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); +begin + OnFindDeclarations:=TheOnFindDeclarations; +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 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 identifier (needed to find CodePos in cache) + while (CodePos.P>1) and (IsIdentChar[Code.Source[CodePos.P-1]]) do + dec(CodePos.P); + if not IsIdentChar[Code.Source[CodePos.P]] then exit; + + // 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; + + // 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; + FCurrent.CodeToolsChangeStep:=GlobalCodeNodeTreeChangeStep; + end; + FCurrent.Add(Item); + + // clean up cache a bit + CleanCache(5); +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. + diff --git a/components/codetools/codeatom.pas b/components/codetools/codeatom.pas index fbf78fb3f3..e65d827954 100644 --- a/components/codetools/codeatom.pas +++ b/components/codetools/codeatom.pas @@ -143,6 +143,7 @@ function AtomPosition(StartPos, EndPos: integer): TAtomPosition; function CodePosition(P: integer; Code: TCodeBuffer): TCodePosition; function CodeXYPosition(X, Y: integer; Code: TCodeBuffer): TCodeXYPosition; function CompareCodeXYPositions(Pos1, Pos2: PCodeXYPosition): integer; +function CompareCodePositions(Pos1, Pos2: PCodePosition): integer; procedure AddCodePosition(var ListOfPCodeXYPosition: TFPList; const NewCodePos: TCodeXYPosition); @@ -194,6 +195,15 @@ begin else Result:=0; end; +function CompareCodePositions(Pos1, Pos2: PCodePosition): integer; +begin + if Pointer(Pos1^.Code)>Pointer(Pos2^.Code) then Result:=1 + else if Pointer(Pos1^.Code)Pos2^.P then Result:=-1 + else Result:=0; +end; + procedure AddCodePosition(var ListOfPCodeXYPosition: TFPList; const NewCodePos: TCodeXYPosition); var diff --git a/components/codetools/codetoolmanager.pas b/components/codetools/codetoolmanager.pas index 21ef11a776..02b71fd0ec 100644 --- a/components/codetools/codetoolmanager.pas +++ b/components/codetools/codetoolmanager.pas @@ -108,6 +108,7 @@ type FWriteExceptions: boolean; FWriteLockCount: integer;// Set/Unset counter FWriteLockStep: integer; // current write lock ID + function GetGlobalCodeNodeTreeChangeStep: integer; function OnScannerGetInitValues(Code: Pointer; out AChangeStep: integer): TExpressionEvaluator; procedure OnDefineTreeReadValue(Sender: TObject; const VariableName: string; @@ -167,6 +168,7 @@ type procedure DeactivateWriteLock; property ChangeStep: integer read FChangeStep; procedure IncreaseChangeStep; + property GlobalCodeNodeTreeChangeStep: integer read GetGlobalCodeNodeTreeChangeStep; // file handling property SourceExtensions: string @@ -2718,8 +2720,8 @@ end; function TCodeToolManager.CreatePrivateMethod(Code: TCodeBuffer; const AClassName, NewMethodName: string; ATypeInfo: PTypeInfo; - UseTypeInfoForParameters: boolean; - const APropertyUnitName, APropertyPath: string): boolean; + UseTypeInfoForParameters: boolean; const APropertyUnitName: string; + const APropertyPath: string): boolean; begin {$IFDEF CTDEBUG} DebugLn('TCodeToolManager.CreatePrivateMethod A'); @@ -4103,6 +4105,11 @@ begin Result:=DefineTree.GetDefinesForVirtualDirectory; end; +function TCodeToolManager.GetGlobalCodeNodeTreeChangeStep: integer; +begin + Result:=CustomCodeTool.GlobalCodeNodeTreeChangeStep; +end; + procedure TCodeToolManager.OnDefineTreeReadValue(Sender: TObject; const VariableName: string; var Value: string; var Handled: boolean); begin @@ -4386,10 +4393,10 @@ end; procedure TCodeToolManager.IncreaseChangeStep; begin - if FChangeStep<>$7fffffff then + if FChangeStep<>High(Integer) then inc(FChangeStep) else - FChangeStep:=-$7fffffff; + FChangeStep:=Low(Integer); end; procedure TCodeToolManager.OnToolGetWriteLockInfo(out WriteLockIsSet: boolean; @@ -4397,7 +4404,7 @@ procedure TCodeToolManager.OnToolGetWriteLockInfo(out WriteLockIsSet: boolean; begin WriteLockIsSet:=FWriteLockCount>0; WriteLockStep:=FWriteLockStep; -//DebugLn(' FWriteLockCount=',FWriteLockCount,' FWriteLockStep=',FWriteLockStep); + //DebugLn(' FWriteLockCount=',FWriteLockCount,' FWriteLockStep=',FWriteLockStep); end; function TCodeToolManager.GetResourceTool: TResourceCodeTool; diff --git a/components/codetools/customcodetool.pas b/components/codetools/customcodetool.pas index 2209cca992..eaeed317fa 100644 --- a/components/codetools/customcodetool.pas +++ b/components/codetools/customcodetool.pas @@ -291,10 +291,10 @@ type ExceptionClass: ECodeToolErrors); virtual; procedure RaiseException(const AMessage: string); virtual; procedure RaiseExceptionFmt(const AMessage: string; - const args : array of const); + const args: array of const); procedure SaveRaiseException(const AMessage: string); virtual; procedure SaveRaiseExceptionFmt(const AMessage: string; - const args : array of const); + const args: array of const); property IgnoreErrorAfter: TCodePosition read FIgnoreErrorAfter write SetIgnoreErrorAfter; procedure ClearIgnoreErrorAfter; @@ -318,9 +318,20 @@ type var RaiseUnhandableExceptions: boolean; + GlobalCodeNodeTreeChangeStep: integer = 0; + +procedure IncreaseGlobalCodeNodeTreeChangeStep; implementation +procedure IncreaseGlobalCodeNodeTreeChangeStep; +begin + if GlobalCodeNodeTreeChangeStep=High(integer) then + GlobalCodeNodeTreeChangeStep:=Low(integer) + else + inc(GlobalCodeNodeTreeChangeStep); +end; + { TCustomCodeTool } @@ -1923,6 +1934,7 @@ begin FTreeChangeStep:=Low(integer) else inc(FTreeChangeStep); + IncreaseGlobalCodeNodeTreeChangeStep; end; procedure TCustomCodeTool.RaiseExceptionInstance(TheException: ECodeToolError); diff --git a/ide/compileroptions.pp b/ide/compileroptions.pp index a0649ce294..bf095b0b3f 100644 --- a/ide/compileroptions.pp +++ b/ide/compileroptions.pp @@ -158,7 +158,7 @@ type TParsedCompilerOptions = class private FGetWritableOutputDirectory: TGetWritableOutputDirectory; - FInvalidateGraphOnChange: boolean; + FInvalidateParseOnChange: boolean; FOnLocalSubstitute: TLocalSubstitutionEvent; public UnparsedValues: array[TParsedCompilerOptString] of string; @@ -185,8 +185,8 @@ type public property OnLocalSubstitute: TLocalSubstitutionEvent read FOnLocalSubstitute write FOnLocalSubstitute; - property InvalidateGraphOnChange: boolean read FInvalidateGraphOnChange - write FInvalidateGraphOnChange; + property InvalidateParseOnChange: boolean read FInvalidateParseOnChange + write FInvalidateParseOnChange; property GetWritableOutputDirectory: TGetWritableOutputDirectory read FGetWritableOutputDirectory write FGetWritableOutputDirectory; end; @@ -265,7 +265,6 @@ type FDefaultMakeOptionsFlags: TCompilerCmdLineOptions; fInheritedOptions: TInheritedCompOptsParseTypesStrings; fInheritedOptParseStamps: integer; - fInheritedOptGraphStamps: integer; fLoaded: Boolean; fOptionsString: String; FParsedOpts: TParsedCompilerOptions; @@ -454,20 +453,18 @@ const ); type - TCompilerGraphStampIncreasedEvent = procedure of object; + TCompilerParseStampIncreasedEvent = procedure of object; TRunCompilerWithOptions = function(ExtTool: TIDEExternalToolOptions; ACompilerOptions: TBaseCompilerOptions): TModalResult of object; var CompilerParseStamp: integer; // TimeStamp of base value for macros - CompilerGraphStamp: integer; // TimeStamp of IDE graph (e.g. packages) OnParseString: TParseStringEvent = nil; - CompilerGraphStampIncreased: TCompilerGraphStampIncreasedEvent = nil; + CompilerParseStampIncreased: TCompilerParseStampIncreasedEvent = nil; RunCompilerWithOptions: TRunCompilerWithOptions = nil; procedure IncreaseCompilerParseStamp; -procedure IncreaseCompilerGraphStamp; function ParseString(Options: TParsedCompilerOptions; const UnparsedValue: string; PlatformIndependent: boolean): string; @@ -506,16 +503,8 @@ begin inc(CompilerParseStamp) else CompilerParseStamp:=MinParseStamp; -end; - -procedure IncreaseCompilerGraphStamp; -begin - if CompilerGraphStampCompilerParseStamp) - or (fInheritedOptGraphStamps<>CompilerGraphStamp) + //QWE or (fInheritedOptGraphStamps<>CompilerGraphStamp) then begin // update inherited options ClearInheritedOptions; @@ -1442,7 +1431,7 @@ begin OptionsList.Free; end; fInheritedOptParseStamps:=CompilerParseStamp; - fInheritedOptGraphStamps:=CompilerGraphStamp; + //QWE fInheritedOptGraphStamps:=CompilerGraphStamp; end; Result:=fInheritedOptions[Parsed][Option]; if RelativeToBaseDir then begin @@ -2816,7 +2805,7 @@ procedure TParsedCompilerOptions.SetUnparsedValue( Option: TParsedCompilerOptString; const NewValue: string); begin if NewValue=UnparsedValues[Option] then exit; - if InvalidateGraphOnChange then IncreaseCompilerGraphStamp; + if InvalidateParseOnChange then IncreaseCompilerParseStamp; if Option=pcosBaseDir then InvalidateFiles else begin @@ -3124,8 +3113,7 @@ end; initialization CompilerParseStamp:=1; - CompilerGraphStamp:=1; - CompilerGraphStampIncreased:=nil; + CompilerParseStampIncreased:=nil; end. diff --git a/ide/lazdoc.pas b/ide/lazdoc.pas index 5de4390a02..2d67923d75 100644 --- a/ide/lazdoc.pas +++ b/ide/lazdoc.pas @@ -32,10 +32,11 @@ interface uses Classes, SysUtils, LCLProc, FileUtil, - CodeTree, CodeToolManager, CodeCache, FileProcs, AvgLvlTree, + CodeAtom, CodeTree, CodeToolManager, CodeCache, CacheCodeTools, + FileProcs, AvgLvlTree, Laz_DOM, Laz_XMLRead, Laz_XMLWrite, MacroIntf, PackageIntf, LazHelpIntf, ProjectIntf, LazIDEIntf, - IDEProcs, PackageDefs, EnvironmentOpts; + CompilerOptions, IDEProcs, PackageDefs, EnvironmentOpts; type { TLazFPDocFile } @@ -52,6 +53,8 @@ type function GetElementWithName(const ElementName: string): TDOMNode; end; + { TLDSourceToFPDocFile - cache item for source to FPDoc file mapping } + TLDSourceToFPDocFile = class public SourceFilename: string; @@ -79,6 +82,8 @@ type private FDocs: TAvgLvlTree;// tree of loaded TLazFPDocFile FHandlers: array[TLazDocManagerHandler] of TMethodList; + FSrcToDocMap: TAvgLvlTree; // tree of TLDSourceToFPDocFile sorted for SourceFilename + FDeclarationCache: TDeclarationInheritanceCache; procedure AddHandler(HandlerType: TLazDocManagerHandler; const AMethod: TMethod; AsLast: boolean = false); procedure RemoveHandler(HandlerType: TLazDocManagerHandler; @@ -89,22 +94,23 @@ type constructor Create; destructor Destroy; override; procedure FreeDocs; + procedure ClearSrcToDocMap; function FindFPDocFile(const Filename: string): TLazFPDocFile; function LoadFPDocFile(const Filename: string; UpdateFromDisk, Revert: Boolean; out ADocFile: TLazFPDocFile; - out UsedCache: boolean): Boolean; + out CacheWasUsed: boolean): Boolean; function GetFPDocFilenameForHelpContext( Context: TPascalHelpContextList; - out UsedCache: boolean): string; + out CacheWasUsed: boolean): string; function GetFPDocFilenameForSource(SrcFilename: string; ResolveIncludeFiles: Boolean; - out UsedCache: boolean): string; + out CacheWasUsed: boolean): string; function CodeNodeToElementName(Tool: TCodeTool; CodeNode: TCodeTreeNode): string; function GetFPDocNode(Tool: TCodeTool; CodeNode: TCodeTreeNode; Complete: boolean; out FPDocFile: TLazFPDocFile; out DOMNode: TDOMNode; - out UsedCache: boolean): TLazDocParseResult; + out CacheWasUsed: boolean): TLazDocParseResult; public // Event lists procedure RemoveAllHandlersOfObject(AnObject: TObject); @@ -121,10 +127,13 @@ var function CompareLazFPDocFilenames(Data1, Data2: Pointer): integer; function CompareAnsistringWithLazFPDocFile(Key, Data: Pointer): integer; +function CompareLDSrc2DocSrcFilenames(Data1, Data2: Pointer): integer; +function CompareAnsistringWithLDSrc2DocSrcFile(Key, Data: Pointer): integer; implementation + function CompareLazFPDocFilenames(Data1, Data2: Pointer): integer; begin Result:=CompareFilenames(TLazFPDocFile(Data1).Filename, @@ -136,6 +145,17 @@ begin Result:=CompareFilenames(AnsiString(Key),TLazFPDocFile(Data).Filename); end; +function CompareLDSrc2DocSrcFilenames(Data1, Data2: Pointer): integer; +begin + Result:=CompareFilenames(TLDSourceToFPDocFile(Data1).SourceFilename, + TLDSourceToFPDocFile(Data2).SourceFilename); +end; + +function CompareAnsistringWithLDSrc2DocSrcFile(Key, Data: Pointer): integer; +begin + Result:=CompareFilenames(AnsiString(Key),TLDSourceToFPDocFile(Data).SourceFilename); +end; + { TLazFPDocFile } destructor TLazFPDocFile.Destroy; @@ -214,12 +234,18 @@ end; constructor TLazDocManager.Create; begin FDocs:=TAvgLvlTree.Create(@CompareLazFPDocFilenames); + FSrcToDocMap:=TAvgLvlTree.Create(@CompareLDSrc2DocSrcFilenames); + FDeclarationCache:=TDeclarationInheritanceCache.Create( + @CodeToolBoss.FindDeclarationAndOverload); end; destructor TLazDocManager.Destroy; begin + ClearSrcToDocMap; FreeDocs; FreeAndNil(FDocs); + FreeAndNil(FSrcToDocMap); + FreeAndNil(FDeclarationCache); inherited Destroy; end; @@ -235,12 +261,12 @@ begin end; function TLazDocManager.LoadFPDocFile(const Filename: string; UpdateFromDisk, - Revert: Boolean; out ADocFile: TLazFPDocFile; out UsedCache: boolean): Boolean; + Revert: Boolean; out ADocFile: TLazFPDocFile; out CacheWasUsed: boolean): Boolean; var MemStream: TMemoryStream; begin Result:=false; - UsedCache:=true; + CacheWasUsed:=true; ADocFile:=FindFPDocFile(Filename); if ADocFile=nil then begin ADocFile:=TLazFPDocFile.Create; @@ -259,7 +285,7 @@ begin // no update needed exit(true); end; - UsedCache:=false; + CacheWasUsed:=false; DebugLn(['TLazDocManager.LoadFPDocFile parsing ',ADocFile.Filename]); CallDocChangeEvents(ldmhDocChanging,ADocFile); @@ -284,24 +310,24 @@ begin end; function TLazDocManager.GetFPDocFilenameForHelpContext( - Context: TPascalHelpContextList; out UsedCache: boolean): string; + Context: TPascalHelpContextList; out CacheWasUsed: boolean): string; var i: Integer; SrcFilename: String; begin Result:=''; - UsedCache:=true; + CacheWasUsed:=true; if Context=nil then exit; for i:=0 to Context.Count-1 do begin if Context.Items[i].Descriptor<>pihcFilename then continue; SrcFilename:=Context.Items[i].Context; - Result:=GetFPDocFilenameForSource(SrcFilename,true,UsedCache); + Result:=GetFPDocFilenameForSource(SrcFilename,true,CacheWasUsed); exit; end; end; function TLazDocManager.GetFPDocFilenameForSource(SrcFilename: string; - ResolveIncludeFiles: Boolean; out UsedCache: boolean): string; + ResolveIncludeFiles: Boolean; out CacheWasUsed: boolean): string; var FPDocName: String; SearchPath: String; @@ -368,9 +394,11 @@ var var CodeBuf: TCodeBuffer; + AVLNode: TAvgLvlTreeNode; + MapEntry: TLDSourceToFPDocFile; begin Result:=''; - UsedCache:=false; + CacheWasUsed:=true; if ResolveIncludeFiles then begin CodeBuf:=CodeToolBoss.FindFile(SrcFilename); @@ -383,6 +411,18 @@ begin end; if not FilenameIsPascalSource(SrcFilename) then exit; + + // first try cache + MapEntry:=nil; + AVLNode:=FSrcToDocMap.FindKey(Pointer(SrcFilename),@CompareAnsistringWithLDSrc2DocSrcFile); + if AVLNode<>nil then begin + MapEntry:=TLDSourceToFPDocFile(AVLNode.Data); + if MapEntry.FPDocFilenameTimeStamp=CompilerParseStamp then begin + Result:=MapEntry.FPDocFilename; + exit; + end; + end; + CacheWasUsed:=false; // first check if the file is owned by any project/package SearchPath:=''; @@ -395,6 +435,15 @@ begin FPDocName:=lowercase(ExtractFileNameOnly(SrcFilename))+'.xml'; DebugLn(['TLazDocManager.GetFPDocFilenameForSource Search ',FPDocName,' in "',SearchPath,'"']); Result:=SearchFileInPath(FPDocName,'',SearchPath,';',ctsfcAllCase); + + // save to cache + if MapEntry=nil then begin + MapEntry:=TLDSourceToFPDocFile.Create; + MapEntry.SourceFilename:=SrcFilename; + FSrcToDocMap.Add(MapEntry); + end; + MapEntry.FPDocFilename:=Result; + MapEntry.FPDocFilenameTimeStamp:=CompilerParseStamp; end; function TLazDocManager.CodeNodeToElementName(Tool: TCodeTool; @@ -424,7 +473,7 @@ end; function TLazDocManager.GetFPDocNode(Tool: TCodeTool; CodeNode: TCodeTreeNode; Complete: boolean; out FPDocFile: TLazFPDocFile; out DOMNode: TDOMNode; - out UsedCache: boolean): TLazDocParseResult; + out CacheWasUsed: boolean): TLazDocParseResult; var SrcFilename: String; FPDocFilename: String; @@ -432,18 +481,18 @@ var begin FPDocFile:=nil; DOMNode:=nil; - UsedCache:=true; + CacheWasUsed:=true; // find corresponding FPDoc file SrcFilename:=Tool.MainFilename; - FPDocFilename:=GetFPDocFilenameForSource(SrcFilename,false,UsedCache); + FPDocFilename:=GetFPDocFilenameForSource(SrcFilename,false,CacheWasUsed); if FPDocFilename='' then exit(ldprFailed); - if (not UsedCache) and (not Complete) then exit(ldprParsing); + if (not CacheWasUsed) and (not Complete) then exit(ldprParsing); // load FPDoc file - if not LoadFPDocFile(FPDocFilename,true,false,FPDocFile,UsedCache) then + if not LoadFPDocFile(FPDocFilename,true,false,FPDocFile,CacheWasUsed) then exit(ldprFailed); - if (not UsedCache) and (not Complete) then exit(ldprParsing); + if (not CacheWasUsed) and (not Complete) then exit(ldprParsing); // find FPDoc node ElementName:=CodeNodeToElementName(Tool,CodeNode); @@ -466,6 +515,11 @@ begin FDocs.FreeAndClear; end; +procedure TLazDocManager.ClearSrcToDocMap; +begin + FSrcToDocMap.FreeAndClear; +end; + procedure TLazDocManager.RemoveAllHandlersOfObject(AnObject: TObject); var HandlerType: TLazDocManagerHandler; diff --git a/ide/main.pp b/ide/main.pp index e170bea94f..db049b3956 100644 --- a/ide/main.pp +++ b/ide/main.pp @@ -491,7 +491,7 @@ type var IsDefined: boolean); procedure CodeToolBossPrepareTree(Sender: TObject); function CTMacroFunctionProject(Data: Pointer): boolean; - procedure OnCompilerGraphStampIncreased; + procedure OnCompilerParseStampIncreased; // MessagesView events procedure MessagesViewSelectionChanged(sender: TObject); @@ -3427,7 +3427,7 @@ begin if frmCompilerOptions.ShowModal=mrOk then begin MainBuildBoss.RescanCompilerDefines(true); Project1.DefineTemplates.AllChanged; - IncreaseCompilerGraphStamp; + IncreaseCompilerParseStamp; end; finally frmCompilerOptions.Free; @@ -3454,7 +3454,7 @@ begin if frmCompilerOptions.ShowModal=mrOk then begin MainBuildBoss.RescanCompilerDefines(true); Project1.DefineTemplates.AllChanged; - IncreaseCompilerGraphStamp; + IncreaseCompilerParseStamp; end; finally frmCompilerOptions.Free; @@ -10867,7 +10867,7 @@ begin CodeToolsOpts.AssignGlobalDefineTemplatesToTree(CodeToolBoss.DefineTree); - CompilerGraphStampIncreased:=@OnCompilerGraphStampIncreased; + CompilerParseStampIncreased:=@OnCompilerParseStampIncreased; // codetools consistency check c:=CodeToolBoss.ConsistencyCheck; @@ -11028,7 +11028,7 @@ begin end; end; -procedure TMainIDE.OnCompilerGraphStampIncreased; +procedure TMainIDE.OnCompilerParseStampIncreased; begin FRebuildingCompilerGraphCodeToolsDefinesNeeded:=true; end; diff --git a/packager/packagedefs.pas b/packager/packagedefs.pas index 0e29a8d7b3..b336e597b9 100644 --- a/packager/packagedefs.pas +++ b/packager/packagedefs.pas @@ -2358,7 +2358,7 @@ begin fPublishOptions:=TPublishPackageOptions.Create(Self); FProvides:=TStringList.Create; Clear; - FUsageOptions.ParsedOpts.InvalidateGraphOnChange:=true; + FUsageOptions.ParsedOpts.InvalidateParseOnChange:=true; end; destructor TLazPackage.Destroy; diff --git a/packager/pkgmanager.pas b/packager/pkgmanager.pas index 9feb2f441d..d1005709a4 100644 --- a/packager/pkgmanager.pas +++ b/packager/pkgmanager.pas @@ -910,7 +910,7 @@ end; procedure TPkgManager.PackageGraphEndUpdate(Sender: TObject; GraphChanged: boolean); begin - if GraphChanged then IncreaseCompilerGraphStamp; + if GraphChanged then IncreaseCompilerParseStamp; if PackageGraphExplorer<>nil then begin if GraphChanged then PackageGraphExplorer.UpdateAll; PackageGraphExplorer.EndUpdate;