MG: added node cache, which accelerates mass find declaration

git-svn-id: trunk@662 -
This commit is contained in:
lazarus 2002-02-05 20:46:51 +00:00
parent 7a654795a8
commit eb0a5dacfc
4 changed files with 245 additions and 85 deletions

View File

@ -469,8 +469,6 @@ begin
end; end;
FCurCodeTool:=TCodeCompletionCodeTool(GetCodeToolForSource(MainCode,true)); FCurCodeTool:=TCodeCompletionCodeTool(GetCodeToolForSource(MainCode,true));
FCurCodeTool.ErrorPosition.Code:=nil; FCurCodeTool.ErrorPosition.Code:=nil;
FCurCodeTool.OnSetGlobalWriteLock:=@OnToolSetWriteLock;
FCurCodeTool.OnGetGlobalWriteLockInfo:=@OnToolGetWriteLockInfo;
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
writeln('[TCodeToolManager.InitCurCodeTool] ',Code.Filename,' ',Code.SourceLength); writeln('[TCodeToolManager.InitCurCodeTool] ',Code.Filename,' ',Code.SourceLength);
{$ENDIF} {$ENDIF}
@ -1358,6 +1356,8 @@ begin
Result.JumpCentered:=FJumpCentered; Result.JumpCentered:=FJumpCentered;
Result.CursorBeyondEOL:=FCursorBeyondEOL; Result.CursorBeyondEOL:=FCursorBeyondEOL;
TFindDeclarationTool(Result).OnGetCodeToolForBuffer:=@OnGetCodeToolForBuffer; TFindDeclarationTool(Result).OnGetCodeToolForBuffer:=@OnGetCodeToolForBuffer;
Result.OnSetGlobalWriteLock:=@OnToolSetWriteLock;
Result.OnGetGlobalWriteLockInfo:=@OnToolGetWriteLockInfo;
end; end;
function TCodeToolManager.OnGetCodeToolForBuffer(Sender: TObject; function TCodeToolManager.OnGetCodeToolForBuffer(Sender: TObject;
@ -1393,6 +1393,7 @@ procedure TCodeToolManager.OnToolGetWriteLockInfo(var WriteLockIsSet: boolean;
begin begin
WriteLockIsSet:=FWriteLockCount>0; WriteLockIsSet:=FWriteLockCount>0;
WriteLockStep:=FWriteLockStep; WriteLockStep:=FWriteLockStep;
//writeln(' FWriteLockCount=',FWriteLockCount,' FWriteLockStep=',FWriteLockStep);
end; end;
procedure TCodeToolManager.OnToolSetWriteLock(Lock: boolean); procedure TCodeToolManager.OnToolSetWriteLock(Lock: boolean);

View File

@ -78,6 +78,7 @@ type
ErrorPosition: TCodeXYPosition; ErrorPosition: TCodeXYPosition;
property Scanner: TLinkScanner read FScanner write SetScanner; property Scanner: TLinkScanner read FScanner write SetScanner;
function MainFilename: string;
function FindDeepestNodeAtPos(P: integer; function FindDeepestNodeAtPos(P: integer;
ExceptionOnNotFound: boolean): TCodeTreeNode; ExceptionOnNotFound: boolean): TCodeTreeNode;
@ -1481,6 +1482,14 @@ begin
if Assigned(OnSetGlobalWriteLock) then OnSetGlobalWriteLock(false); if Assigned(OnSetGlobalWriteLock) then OnSetGlobalWriteLock(false);
end; end;
function TCustomCodeTool.MainFilename: string;
begin
if (Scanner<>nil) and (Scanner.MainCode<>nil) then
Result:=TCodeBuffer(Scanner.MainCode).Filename
else
Result:='(unknown mainfilename)';
end;
{ ECodeToolError } { ECodeToolError }
constructor ECodeToolError.Create(ASender: TCustomCodeTool; constructor ECodeToolError.Create(ASender: TCustomCodeTool;

View File

@ -70,30 +70,31 @@ type
{ {
2. code tree node cache: 2. code tree node cache:
Some nodes (class, interface, implementation, program, type, var, const, Some nodes (class, proc, record) contain a node cache. A node cache caches
...) contain a node search results of searched identifiers for child nodes.
cache. A node cache caches identifier requests of direct child nodes.
Because node caches can store information of used units, the cahce must be Every entry in the node cache describes the following relationship:
Identifier+Range -> Source Position
and can be interpreted as:
Identifier is a PChar to the beginning of an identifier string.
Range is a clenaed source range (CleanStartPos-CleanEndPos).
Source position is a tuple of NewTool, NewNode, NewCleanPos.
If the current context node is a child of a caching node and it is in the
range, then the result is valid. If NewNode=nil then there is no such
identifier valid at the context node.
Every node that define local identifiers contains a node cache.
These are: class, proc, record, withstatement
Because node caches can store information of used units, the cache must be
deleted every time a used unit is changed. Currently all node caches are deleted every time a used unit is changed. Currently all node caches are
resetted every time the GlobalWriteLock increases. resetted every time the GlobalWriteLock increases.
every 'cache' node get a list of
Identifier+CleanBackwardPos+CleanForwardPos -> TFindContext
This information means: if an identifier is searched at a
child node (not sub child node!) within the bounds, the cached
FindContext is valid.
'cache' nodes are:
- section nodes e.g. interface, program, ...
- class nodes
this cache must be deleted, every time the code tree changes, or
one of the used units changes.
} }
const
AllNodeCacheDescs = [ctnClass, ctnProcedure, ctnRecordType, ctnWithStatement];
type
PCodeTreeNodeCacheEntry = ^TCodeTreeNodeCacheEntry; PCodeTreeNodeCacheEntry = ^TCodeTreeNodeCacheEntry;
TCodeTreeNodeCacheEntry = record TCodeTreeNodeCacheEntry = record
Identifier: PChar; Identifier: PChar;
@ -116,6 +117,8 @@ type
function FindAVLNode(Identifier: PChar; CleanPos: integer): TAVLTreeNode; function FindAVLNode(Identifier: PChar; CleanPos: integer): TAVLTreeNode;
function FindAVLNodeInRange(Identifier: PChar; function FindAVLNodeInRange(Identifier: PChar;
CleanStartPos, CleanEndPos: integer): TAVLTreeNode; CleanStartPos, CleanEndPos: integer): TAVLTreeNode;
function FindInRange(Identifier: PChar;
CleanStartPos, CleanEndPos: integer): PCodeTreeNodeCacheEntry;
function FindNearestAVLNode(Identifier: PChar; function FindNearestAVLNode(Identifier: PChar;
CleanStartPos, CleanEndPos: integer; InFront: boolean): TAVLTreeNode; CleanStartPos, CleanEndPos: integer; InFront: boolean): TAVLTreeNode;
function FindNearest(Identifier: PChar; function FindNearest(Identifier: PChar;
@ -132,11 +135,15 @@ type
procedure WriteDebugReport(const Prefix: string); procedure WriteDebugReport(const Prefix: string);
function ConsistencyCheck: integer; function ConsistencyCheck: integer;
end; end;
const
// all node types which can hold a cache
AllNodeCacheDescs = [ctnClass, ctnInterface, ctnInitialization, ctnProgram];
{
3. Base type node cache
ToDo:
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
type type
TGlobalIdentifierTree = class TGlobalIdentifierTree = class
@ -473,7 +480,7 @@ end;
constructor TCodeTreeNodeCache.Create(AnOwner: TCodeTreeNode); constructor TCodeTreeNodeCache.Create(AnOwner: TCodeTreeNode);
begin begin
inherited Create; inherited Create;
Owner:=AnOwner; if AnOwner<>nil then BindToOwner(AnOwner);
end; end;
destructor TCodeTreeNodeCache.Destroy; destructor TCodeTreeNodeCache.Destroy;
@ -652,11 +659,13 @@ var
Entry: PCodeTreeNodeCacheEntry; Entry: PCodeTreeNodeCacheEntry;
begin begin
Result:=FindNearestAVLNode(Identifier,CleanStartPos,CleanEndPos,true); Result:=FindNearestAVLNode(Identifier,CleanStartPos,CleanEndPos,true);
Entry:=PCodeTreeNodeCacheEntry(Result.Data); if Result<>nil then begin
if (CleanStartPos>Entry^.CleanEndPos) Entry:=PCodeTreeNodeCacheEntry(Result.Data);
or (CleanEndPos<Entry^.CleanStartPos) then begin if (CleanStartPos>Entry^.CleanEndPos)
// node is not in range or (CleanEndPos<Entry^.CleanStartPos) then begin
Result:=nil; // node is not in range
Result:=nil;
end;
end; end;
end; end;
@ -684,7 +693,6 @@ begin
else begin else begin
// cached result with identifier found // cached result with identifier found
// -> check range // -> check range
NextNode:=Result;
if CleanStartPos>=Entry^.CleanEndPos then begin if CleanStartPos>=Entry^.CleanEndPos then begin
NextNode:=FItems.FindSuccessor(Result); NextNode:=FItems.FindSuccessor(Result);
DirectionSucc:=true; DirectionSucc:=true;
@ -698,7 +706,6 @@ begin
while (NextNode<>nil) do begin while (NextNode<>nil) do begin
Entry:=PCodeTreeNodeCacheEntry(NextNode.Data); Entry:=PCodeTreeNodeCacheEntry(NextNode.Data);
if CompareIdentifiers(Identifier,Entry^.Identifier)<>0 then begin if CompareIdentifiers(Identifier,Entry^.Identifier)<>0 then begin
Result:=nil;
exit; exit;
end; end;
Result:=NextNode; Result:=NextNode;
@ -712,6 +719,7 @@ begin
else else
NextNode:=FItems.FindPrecessor(Result); NextNode:=FItems.FindPrecessor(Result);
end; end;
exit;
end; end;
end; end;
end else begin end else begin
@ -787,6 +795,17 @@ begin
Result:=nil; Result:=nil;
end; end;
function TCodeTreeNodeCache.FindInRange(Identifier: PChar; CleanStartPos,
CleanEndPos: integer): PCodeTreeNodeCacheEntry;
var Node: TAVLTreeNode;
begin
Node:=FindAVLNodeInRange(Identifier,CleanStartPos,CleanEndPos);
if Node<>nil then
Result:=PCodeTreeNodeCacheEntry(Node.Data)
else
Result:=nil;
end;
{ TNodeCacheMemManager } { TNodeCacheMemManager }
procedure TNodeCacheMemManager.DisposeNode(Node: TCodeTreeNodeCache); procedure TNodeCacheMemManager.DisposeNode(Node: TCodeTreeNodeCache);

View File

@ -45,6 +45,7 @@ interface
{ $DEFINE ShowExprEval} { $DEFINE ShowExprEval}
{ $DEFINE ShowFoundIdentifier} { $DEFINE ShowFoundIdentifier}
{ $DEFINE ShowCachedIdentifiers} { $DEFINE ShowCachedIdentifiers}
{ $DEFINE ShowNodeCache}
uses uses
{$IFDEF MEM_CHECK} {$IFDEF MEM_CHECK}
@ -230,6 +231,7 @@ type
FOnGetUnitSourceSearchPath: TOnGetSearchPath; FOnGetUnitSourceSearchPath: TOnGetSearchPath;
FFirstNodeCache: TCodeTreeNodeCache; FFirstNodeCache: TCodeTreeNodeCache;
FLastNodeCachesGlobalWriteLockStep: integer; FLastNodeCachesGlobalWriteLockStep: integer;
FRootNodeCache: TCodeTreeNodeCache;
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
DebugPrefix: string; DebugPrefix: string;
procedure IncPrefix; procedure IncPrefix;
@ -277,6 +279,12 @@ type
protected protected
procedure DoDeleteNodes; override; procedure DoDeleteNodes; override;
procedure ClearNodeCaches(Force: boolean); procedure ClearNodeCaches(Force: boolean);
function CreateNewNodeCache(Node: TCodeTreeNode): TCodeTreeNodeCache;
function GetNodeCache(Node: TCodeTreeNode;
CreateIfNotExists: boolean): TCodeTreeNodeCache;
procedure AddResultToNodeCaches(Identifier: PChar;
StartNode, EndNode: TCodeTreeNode; SearchedForward: boolean;
Params: TFindDeclarationParams);
function FindDeclarationOfIdentifier( function FindDeclarationOfIdentifier(
Params: TFindDeclarationParams): boolean; Params: TFindDeclarationParams): boolean;
function FindContextNodeAtCursor( function FindContextNodeAtCursor(
@ -339,7 +347,7 @@ const
fdfClassPrivate]; fdfClassPrivate];
fdfGlobals = [fdfExceptionOnNotFound, fdfIgnoreUsedUnits]; fdfGlobals = [fdfExceptionOnNotFound, fdfIgnoreUsedUnits];
fdfGlobalsSameIdent = fdfGlobals+[fdfIgnoreMissingParams,fdfFirstIdentFound, fdfGlobalsSameIdent = fdfGlobals+[fdfIgnoreMissingParams,fdfFirstIdentFound,
fdfOnlyCompatibleProc]; fdfOnlyCompatibleProc,fdfSearchInAncestors];
fdfDefaultForExpressions = [fdfSearchInParentNodes,fdfSearchInAncestors, fdfDefaultForExpressions = [fdfSearchInParentNodes,fdfSearchInAncestors,
fdfExceptionOnNotFound]+fdfAllClassVisibilities; fdfExceptionOnNotFound]+fdfAllClassVisibilities;
@ -430,6 +438,10 @@ writeln('TFindDeclarationTool.FindDeclaration D CursorNode=',NodeDescriptionAsSt
end; end;
if CursorNode.Desc=ctnProcedureHead then if CursorNode.Desc=ctnProcedureHead then
CursorNode:=CursorNode.Parent; CursorNode:=CursorNode.Parent;
if CursorNode.Desc=ctnProcedure then begin
BuildSubTreeForProcHead(CursorNode);
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
end;
MoveCursorToCleanPos(CleanCursorPos); MoveCursorToCleanPos(CleanCursorPos);
while (CurPos.StartPos>1) and (IsIdentChar[Src[CurPos.StartPos-1]]) do while (CurPos.StartPos>1) and (IsIdentChar[Src[CurPos.StartPos-1]]) do
dec(CurPos.StartPos); dec(CurPos.StartPos);
@ -787,40 +799,41 @@ function TFindDeclarationTool.FindIdentifierInContext(
var LastContextNode, StartContextNode, ContextNode: TCodeTreeNode; var LastContextNode, StartContextNode, ContextNode: TCodeTreeNode;
IsForward: boolean; IsForward: boolean;
IdentifierFoundResult: TIdentifierFoundResult; IdentifierFoundResult: TIdentifierFoundResult;
ParentsNodeCache: TCodeTreeNodeCache; LastNodeCache: TCodeTreeNodeCache;
NearestNodeCacheEntry: PCodeTreeNodeCacheEntry; LastCacheEntry: PCodeTreeNodeCacheEntry;
function FindInNodeCache: boolean; function FindInNodeCache: boolean;
var Node: TCodeTreeNode; var
NodeCache: TCodeTreeNodeCache;
begin begin
Result:=false; Result:=false;
Node:=ContextNode.Parent; NodeCache:=GetNodeCache(ContextNode,false);
if (Node<>nil) and (Node.Desc in [ctnClassPublic,ctnClassPrivate, if (NodeCache<>LastNodeCache) then begin
ctnClassProtected,ctnClassPublished]) // NodeCache changed -> search nearest cache entry for the identifier
then LastNodeCache:=NodeCache;
Node:=Node.Parent; if NodeCache<>nil then begin
if (Node<>nil) and (Node.Cache<>nil) then begin LastCacheEntry:=NodeCache.FindNearest(Params.identifier,
// parent node has a cache object ContextNode.StartPos,ContextNode.EndPos,
if (Node.Cache is TCodeTreeNodeCache) then begin not (fdfSearchForward in Params.Flags));
// parent has node cache end else
// -> search if result already in cache LastCacheEntry:=nil;
if ParentsNodeCache<>TCodeTreeNodeCache(Node.Cache) then begin end;
// parent cache changed -> search new nearest node if (LastCacheEntry<>nil)
ParentsNodeCache:=TCodeTreeNodeCache(Node.Cache); and (LastCacheEntry^.CleanStartPos<ContextNode.EndPos)
NearestNodeCacheEntry:=ParentsNodeCache.FindNearest( and (LastCacheEntry^.CleanEndPos>ContextNode.StartPos)
Params.Identifier, then begin
ContextNode.StartPos,ContextNode.EndPos, // cached result found
not (fdfSearchForward in Params.Flags)); Params.SetResult(LastCacheEntry);
end; {$IFDEF ShowNodeCache}
if (NearestNodeCacheEntry<>nil) writeln(':::: TFindDeclarationTool.FindIdentifierInContext.FindInNodeCache');
and (NearestNodeCacheEntry^.CleanStartPos<ContextNode.EndPos) writeln(' Ident=',GetIdentifier(Params.Identifier),
and (NearestNodeCacheEntry^.CleanEndPos>ContextNode.StartPos) then begin ' ContextNode=',ContextNode.DescAsString,
// cached result found ' Self=',MainFilename);
Params.SetResult(NearestNodeCacheEntry); if (Params.NewNode<>nil) then
Result:=true; writeln(' NewTool=',Params.NewCodeTool.MainFilename,
exit; ' NewNode=',Params.NewNode.DescAsString);
end; {$ENDIF}
end; Result:=true;
end; end;
end; end;
@ -828,14 +841,13 @@ begin
ContextNode:=Params.ContextNode; ContextNode:=Params.ContextNode;
StartContextNode:=ContextNode; StartContextNode:=ContextNode;
Result:=false; Result:=false;
if ContextNode=nil then begin
if ContextNode<>nil then begin RaiseException('[TFindDeclarationTool.FindIdentifierInContext] '
+' internal error: Params.ContextNode=nil');
// initialize cache search end;
ParentsNodeCache:=nil; try
NearestNodeCacheEntry:=nil; LastNodeCache:=nil;
LastCacheEntry:=nil;
// search ...
repeat repeat
{$IFDEF ShowTriedContexts} {$IFDEF ShowTriedContexts}
writeln('[TFindDeclarationTool.FindIdentifierInContext] A Ident=', writeln('[TFindDeclarationTool.FindIdentifierInContext] A Ident=',
@ -849,8 +861,10 @@ if (ContextNode.Desc=ctnClass) then
writeln(' ContextNode.LastChild=',ContextNode.LastChild<>nil); writeln(' ContextNode.LastChild=',ContextNode.LastChild<>nil);
{$ENDIF} {$ENDIF}
// search in cache // search in cache
Result:=FindInNodeCache; if FindInNodeCache then begin
if Result then exit; Result:=(Params.NewNode<>nil);
exit;
end;
// search identifier in current context // search identifier in current context
LastContextNode:=ContextNode; LastContextNode:=ContextNode;
@ -864,6 +878,9 @@ if (ContextNode.Desc=ctnClass) then
ctnRecordType, ctnRecordCase, ctnRecordVariant, ctnRecordType, ctnRecordCase, ctnRecordVariant,
ctnParameterList: ctnParameterList:
begin begin
// these nodes build a parent-child relationship. But in pascal
// they just define a range and not a context.
// -> search in all childs
if ContextNode.Desc=ctnClass then begin if ContextNode.Desc=ctnClass then begin
// just-in-time parsing for class node // just-in-time parsing for class node
BuildSubTreeForClass(ContextNode); BuildSubTreeForClass(ContextNode);
@ -1093,9 +1110,19 @@ writeln('[TFindDeclarationTool.FindIdentifierInContext] Searching in Parent Con
until false; until false;
end; end;
until ContextNode=nil; until ContextNode=nil;
end else begin
// DeepestNode=nil -> ignore finally
if Result and (not (fdfDoNotCache in Params.NewFlags)) then begin
// add result to caches
AddResultToNodeCaches(Params.Identifier,StartContextNode,ContextNode,
fdfSearchForward in Params.Flags,Params);
end;
end; end;
// if we are here, the identifier was not found
// add result to cache
AddResultToNodeCaches(Params.Identifier,StartContextNode,ContextNode,
fdfSearchForward in Params.Flags,nil);
if fdfExceptionOnNotFound in Params.Flags then begin if fdfExceptionOnNotFound in Params.Flags then begin
if Params.IdentifierTool.IsPCharInSrc(Params.Identifier) then if Params.IdentifierTool.IsPCharInSrc(Params.Identifier) then
Params.IdentifierTool.MoveCursorToCleanPos(Params.Identifier); Params.IdentifierTool.MoveCursorToCleanPos(Params.Identifier);
@ -1593,7 +1620,7 @@ begin
end; end;
AddNodeToStack(@NodeStack,Result.Node); AddNodeToStack(@NodeStack,Result.Node);
{$IFDEF ShowTriedContexts} {$IFDEF ShowTriedContexts}
writeln('[TFindDeclarationTool.FindBaseTypeOfNode] LOOP Result=',Result.Node.DescAsString); writeln('[TFindDeclarationTool.FindBaseTypeOfNode] LOOP Result=',Result.Node.DescAsString,' ',HexStr(Cardinal(Result.Node),8));
{$ENDIF} {$ENDIF}
if (Result.Node.Desc in AllIdentifierDefinitions) then begin if (Result.Node.Desc in AllIdentifierDefinitions) then begin
// instead of variable/const/type definition, return the type // instead of variable/const/type definition, return the type
@ -1603,10 +1630,12 @@ writeln('[TFindDeclarationTool.FindBaseTypeOfNode] LOOP Result=',Result.Node.Des
and ((Result.Node.SubDesc and ctnsForwardDeclaration)>0) then and ((Result.Node.SubDesc and ctnsForwardDeclaration)>0) then
begin begin
// search the real class // search the real class
{$IFDEF ShowTriedContexts}
writeln('[TFindDeclarationTool.FindBaseTypeOfNode] Class is forward');
{$ENDIF}
// ToDo: check for circles in ancestor chain // ToDo: check for circles in ancestor chain
ClassIdentNode:=Result.Node.Parent; ClassIdentNode:=Result.Node.Parent;
if (ClassIdentNode=nil) or (not (ClassIdentNode.Desc=ctnTypeDefinition)) if (ClassIdentNode=nil) or (not (ClassIdentNode.Desc=ctnTypeDefinition))
then begin then begin
@ -1619,7 +1648,8 @@ writeln('[TFindDeclarationTool.FindBaseTypeOfNode] LOOP Result=',Result.Node.Des
Params.SetIdentifier(Self,@Src[ClassIdentNode.StartPos], Params.SetIdentifier(Self,@Src[ClassIdentNode.StartPos],
@CheckSrcIdentifier); @CheckSrcIdentifier);
Params.Flags:=[fdfSearchInParentNodes,fdfSearchForward, Params.Flags:=[fdfSearchInParentNodes,fdfSearchForward,
fdfIgnoreUsedUnits,fdfExceptionOnNotFound] fdfIgnoreUsedUnits,fdfExceptionOnNotFound,
fdfIgnoreCurContextNode]
+(fdfGlobals*Params.Flags); +(fdfGlobals*Params.Flags);
Params.ContextNode:=ClassIdentNode; Params.ContextNode:=ClassIdentNode;
FindIdentifierInContext(Params); FindIdentifierInContext(Params);
@ -2434,6 +2464,7 @@ writeln(DebugPrefix,'TFindDeclarationTool.FindIdentifierInInterface',
// ToDo: build codetree for ppu, ppw, dcu files // ToDo: build codetree for ppu, ppw, dcu files
// build tree for pascal source // build tree for pascal source
ClearNodeCaches(false);
BuildTree(true); BuildTree(true);
// search identifier in cache // search identifier in cache
@ -3112,6 +3143,7 @@ writeln('[TFindDeclarationTool.CheckSrcIdentifier]',
Params.IdentifierTool.ReadNextAtom; Params.IdentifierTool.ReadNextAtom;
ExprInputList:=Params.IdentifierTool.CreateParamExprList( ExprInputList:=Params.IdentifierTool.CreateParamExprList(
Params.IdentifierTool.CurPos.EndPos,Params); Params.IdentifierTool.CurPos.EndPos,Params);
Params.Load(OldInput);
// create compatibility lists // create compatibility lists
CompListSize:=SizeOf(TTypeCompatibility)*ExprInputList.Count; CompListSize:=SizeOf(TTypeCompatibility)*ExprInputList.Count;
if CompListSize>0 then begin if CompListSize>0 then begin
@ -3121,7 +3153,6 @@ writeln('[TFindDeclarationTool.CheckSrcIdentifier]',
BestCompatibilityList:=nil; BestCompatibilityList:=nil;
CurCompatibilityList:=nil; CurCompatibilityList:=nil;
end; end;
Params.Load(OldInput);
try try
Include(Params.Flags,fdfFirstIdentFound); Include(Params.Flags,fdfFirstIdentFound);
// check the first proc for compatibility // check the first proc for compatibility
@ -3550,7 +3581,7 @@ begin
exit; exit;
end else begin end else begin
// this is the first check in this GlobalWriteLockStep // this is the first check in this GlobalWriteLockStep
FLastNodecachesGlobalWriteLockStep:=GlobalWriteLockStep; FLastNodeCachesGlobalWriteLockStep:=GlobalWriteLockStep;
// proceed normally ... // proceed normally ...
end; end;
end; end;
@ -3561,6 +3592,10 @@ begin
FFirstNodeCache:=NodeCache.Next; FFirstNodeCache:=NodeCache.Next;
NodeCacheMemManager.DisposeNode(NodeCache); NodeCacheMemManager.DisposeNode(NodeCache);
end; end;
if FRootNodeCache<>nil then begin
NodeCacheMemManager.DisposeNode(FRootNodeCache);
FRootNodeCache:=nil;
end;
end; end;
function TFindDeclarationTool.ConsistencyCheck: integer; function TFindDeclarationTool.ConsistencyCheck: integer;
@ -3588,6 +3623,102 @@ begin
ClearNodeCaches(false); ClearNodeCaches(false);
end; end;
function TFindDeclarationTool.GetNodeCache(Node: TCodeTreeNode;
CreateIfNotExists: boolean): TCodeTreeNodeCache;
begin
while (Node<>nil) and (not (Node.Desc in AllNodeCacheDescs)) do
Node:=Node.Parent;
if Node<>nil then begin
if (Node.Cache=nil) and CreateIfNotExists then
CreateNewNodeCache(Node);
if (Node.Cache<>nil) and (Node.Cache is TCodeTreeNodeCache) then
Result:=TCodeTreeNodeCache(Node.Cache)
else
Result:=nil;
end else begin
if (FRootNodeCache=nil) and CreateIfNotExists then
FRootNodeCache:=CreateNewNodeCache(nil);
Result:=FRootNodeCache;
end;
end;
procedure TFindDeclarationTool.AddResultToNodeCaches(Identifier: PChar;
StartNode, EndNode: TCodeTreeNode; SearchedForward: boolean;
Params: TFindDeclarationParams);
var Node: TCodeTreeNode;
CurNodeCache, LastNodeCache: TCodeTreeNodeCache;
CleanStartPos, CleanEndPos: integer;
NewNode: TCodeTreeNode;
NewTool: TPascalParserTool;
NewCleanPos: integer;
begin
{$IFDEF ShowNodeCache}
write('TFindDeclarationTool.AddResultToNodeCaches ',
' Ident=',GetIdentifier(Identifier),
' StartNode=',StartNode.DescAsString,'="',copy(Src,StartNode.StartPos,12),'"');
if EndNode<>nil then
write(' EndNode=',EndNode.DescAsString,'="',copy(Src,EndNode.StartPos,12),'"')
else
write(' EndNode=nil');
write(' SearchedForward=',SearchedForward);
writeln('');
writeln(' Self=',MainFilename);
if Params<>nil then begin
writeln(' NewNode=',Params.NewNode.DescAsString,
' NewTool=',Params.NewCodeTool.MainFilename);
end else begin
writeln(' NOT FOUND');
end;
{$ENDIF}
Node:=StartNode;
LastNodeCache:=nil;
if Params<>nil then begin
NewNode:=Params.NewNode;
NewTool:=Params.NewCodeTool;
NewCleanPos:=Params.NewCleanPos;
end else begin
NewNode:=nil;
NewTool:=nil;
end;
CleanStartPos:=StartNode.StartPos;
CleanEndPos:=StartNode.EndPos;
if EndNode<>nil then begin
if EndNode.StartPos<CleanStartPos then
CleanStartPos:=EndNode.StartPos;
if EndNode.EndPos>CleanEndPos then
CleanEndPos:=EndNode.EndPos;
end else begin
if not SearchedForward then
CleanStartPos:=1
else
CleanEndPos:=SrcLen+1;
end;
while (Node<>nil) do begin
if (Node.Desc in AllNodeCacheDescs) then begin
if (Node.Cache=nil) then
CreateNewNodeCache(Node);
if (Node.Cache is TCodeTreeNodeCache) then begin
CurNodeCache:=TCodeTreeNodeCache(Node.Cache);
if LastNodeCache<>CurNodeCache then begin
CurNodeCache.Add(Identifier,CleanStartPos,CleanEndPos,
NewNode,NewTool,NewCleanPos);
LastNodeCache:=CurNodeCache;
end;
end;
end;
Node:=Node.Parent;
if (EndNode<>nil) and (Node=EndNode.Parent) then break;
end;
end;
function TFindDeclarationTool.CreateNewNodeCache(
Node: TCodeTreeNode): TCodeTreeNodeCache;
begin
Result:=TCodeTreeNodeCache.Create(Node);
Result.Next:=FFirstNodeCache;
FFirstNodeCache:=Result;
end;
{ TFindDeclarationParams } { TFindDeclarationParams }