MG: fixed node cache search range calculation

git-svn-id: trunk@1616 -
This commit is contained in:
lazarus 2002-04-18 06:26:05 +00:00
parent 591eaa3d79
commit 4409ebfe2d
4 changed files with 169 additions and 101 deletions

View File

@ -123,6 +123,7 @@ procedure GetLineStartEndAtPosition(const Source:string; Position:integer;
var LineStart,LineEnd:integer); var LineStart,LineEnd:integer);
procedure GetIdentStartEndAtPosition(const Source:string; Position:integer; procedure GetIdentStartEndAtPosition(const Source:string; Position:integer;
var IdentStart,IdentEnd:integer); var IdentStart,IdentEnd:integer);
function GetIdentLen(Identifier: PChar): integer;
function LineEndCount(const Txt: string; var LengthOfLastLine:integer): integer; function LineEndCount(const Txt: string; var LengthOfLastLine:integer): integer;
function FindFirstNonSpaceCharInLine(const Source: string; function FindFirstNonSpaceCharInLine(const Source: string;
Position: integer): integer; Position: integer): integer;
@ -911,6 +912,13 @@ begin
inc(IdentEnd); inc(IdentEnd);
end; end;
function GetIdentLen(Identifier: PChar): integer;
begin
Result:=0;
if Identifier=nil then exit;
while (IsIDChar[Identifier[Result]]) do inc(Result);
end;
function ReadNextPascalAtom(const Source:string; function ReadNextPascalAtom(const Source:string;
var Position,AtomStart:integer):string; var Position,AtomStart:integer):string;
var DirectiveName:string; var DirectiveName:string;

View File

@ -174,8 +174,10 @@ type
function Next: TCodeTreeNode; function Next: TCodeTreeNode;
function Prior: TCodeTreeNode; function Prior: TCodeTreeNode;
function HasAsParent(Node: TCodeTreeNode): boolean; function HasAsParent(Node: TCodeTreeNode): boolean;
function HasAsChild(Node: TCodeTreeNode): boolean;
function HasParentOfType(ParentDesc: TCodeTreeNodeDesc): boolean; function HasParentOfType(ParentDesc: TCodeTreeNodeDesc): boolean;
function GetNodeOfType(ADesc: TCodeTreeNodeDesc): TCodeTreeNode; function GetNodeOfType(ADesc: TCodeTreeNodeDesc): TCodeTreeNode;
function GetLevel: integer;
function DescAsString: string; function DescAsString: string;
procedure Clear; procedure Clear;
constructor Create; constructor Create;
@ -416,6 +418,13 @@ begin
end; end;
end; end;
function TCodeTreeNode.HasAsChild(Node: TCodeTreeNode): boolean;
begin
Result:=false;
if Node=nil then exit;
Result:=Node.HasAsParent(Self);
end;
function TCodeTreeNode.HasParentOfType(ParentDesc: TCodeTreeNodeDesc): boolean; function TCodeTreeNode.HasParentOfType(ParentDesc: TCodeTreeNodeDesc): boolean;
var ANode: TCodeTreeNode; var ANode: TCodeTreeNode;
begin begin
@ -433,6 +442,17 @@ begin
Result:=Result.Parent; Result:=Result.Parent;
end; end;
function TCodeTreeNode.GetLevel: integer;
var ANode: TCodeTreeNode;
begin
Result:=0;
ANode:=Parent;
while ANode<>nil do begin
inc(Result);
ANode:=ANode.Parent;
end;
end;
function TCodeTreeNode.DescAsString: string; function TCodeTreeNode.DescAsString: string;
begin begin
Result:=NodeDescriptionAsString(Desc); Result:=NodeDescriptionAsString(Desc);

View File

@ -328,7 +328,7 @@ type
Result: TFindContext); Result: TFindContext);
function GetNodeCache(Node: TCodeTreeNode; function GetNodeCache(Node: TCodeTreeNode;
CreateIfNotExists: boolean): TCodeTreeNodeCache; CreateIfNotExists: boolean): TCodeTreeNodeCache;
procedure AddResultToNodeCaches(Identifier: PChar; procedure AddResultToNodeCaches(
StartNode, EndNode: TCodeTreeNode; SearchedForward: boolean; StartNode, EndNode: TCodeTreeNode; SearchedForward: boolean;
Params: TFindDeclarationParams; SearchRangeFlags: TNodeCacheEntryFlags); Params: TFindDeclarationParams; SearchRangeFlags: TNodeCacheEntryFlags);
protected protected
@ -570,8 +570,78 @@ function TFindDeclarationTool.FindDeclaration(CursorPos: TCodeXYPosition;
var CleanCursorPos: integer; var CleanCursorPos: integer;
CursorNode, ClassNode: TCodeTreeNode; CursorNode, ClassNode: TCodeTreeNode;
Params: TFindDeclarationParams; Params: TFindDeclarationParams;
SearchAlsoInCurContext: boolean; DirectSearch: boolean;
SearchInAncestors: boolean;
procedure CheckIfCursorInClassNode;
begin
ClassNode:=CursorNode.GetNodeOfType(ctnClass);
if ClassNode<>nil then begin
// cursor is in class/object definition
if (ClassNode.SubDesc and ctnsForwardDeclaration)=0 then begin
// parse class and build CodeTreeNodes for all properties/methods
BuildSubTreeForClass(ClassNode);
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
if (CursorNode.Desc=ctnClass)
and (CleanCursorPos<ClassNode.FirstChild.StartPos) then begin
// identifier is an ancestor/interface identifier
DirectSearch:=true;
end;
end;
end;
end;
procedure CheckIfCursorInBeginNode;
begin
if CursorNode.Desc=ctnBeginBlock then begin
BuildSubTreeForBeginBlock(CursorNode);
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
end;
end;
procedure CheckIfCursorInProcNode;
var IsMethod: boolean;
begin
if CursorNode.Desc=ctnProcedureHead then
CursorNode:=CursorNode.Parent;
if CursorNode.Desc=ctnProcedure then begin
BuildSubTreeForProcHead(CursorNode);
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
// check if cursor on proc name
if (CursorNode.Desc=ctnProcedureHead)
and (CleanCursorPos>=CursorNode.StartPos) then begin
MoveCursorToNodeStart(CursorNode);
ReadNextAtom;
IsMethod:=false;
if AtomIsIdentifier(false) then begin
ReadNextAtom;
if AtomIsChar('.') then begin
ReadNextAtom;
ReadNextAtom;
IsMethod:=true;
end;
end;
if (CurPos.StartPos>CleanCursorPos) and (not IsMethod) then begin
// cursor on proc name
// -> ignore proc name and search overloaded identifier
DirectSearch:=true;
end;
end;
if CursorNode.Desc=ctnProcedureHead then
CursorNode:=CursorNode.Parent;
end;
end;
procedure CheckIfCursorInPropertyNode;
begin
if CursorNode.Desc=ctnProperty then begin
MoveCursorToNodeStart(CursorNode);
ReadNextAtom; // read 'property'
ReadNextAtom; // read property name
if CleanCursorPos<CurPos.EndPos then
DirectSearch:=true;
end;
end;
begin begin
Result:=false; Result:=false;
ActivateGlobalWriteLock; ActivateGlobalWriteLock;
@ -602,68 +672,18 @@ begin
Result:=FindDeclarationInUsesSection(CursorNode,CleanCursorPos, Result:=FindDeclarationInUsesSection(CursorNode,CleanCursorPos,
NewPos,NewTopLine); NewPos,NewTopLine);
end else begin end else begin
SearchAlsoInCurContext:=true; DirectSearch:=false;
SearchInAncestors:=true; CheckIfCursorInClassNode;
// first test if in a class CheckIfCursorInBeginNode;
ClassNode:=CursorNode; CheckIfCursorInProcNode;
while (ClassNode<>nil) and (ClassNode.Desc<>ctnClass) do CheckIfCursorInPropertyNode;
ClassNode:=ClassNode.Parent; // set cursor
if ClassNode<>nil then begin
// cursor is in class/object definition
if (ClassNode.SubDesc and ctnsForwardDeclaration)=0 then begin
// parse class and build CodeTreeNodes for all properties/methods
BuildSubTreeForClass(ClassNode);
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
if (CursorNode.Desc=ctnClass)
and (CleanCursorPos<ClassNode.FirstChild.StartPos) then begin
// identifier is an ancestor/interface identifier
SearchAlsoInCurContext:=false;
SearchInAncestors:=false;
end;
end;
end;
if CursorNode.Desc=ctnBeginBlock then begin
BuildSubTreeForBeginBlock(CursorNode);
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
end;
if CursorNode.Desc=ctnProcedureHead then
CursorNode:=CursorNode.Parent;
if CursorNode.Desc=ctnProcedure then begin
BuildSubTreeForProcHead(CursorNode);
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
// check if cursor on proc name
if (CursorNode.Desc=ctnProcedureHead)
and (CleanCursorPos>CursorNode.StartPos) then begin
MoveCursorToNodeStart(CursorNode);
ReadNextAtom;
if AtomIsIdentifier(false) then begin
ReadNextAtom;
if AtomIsChar('.') then begin
ReadNextAtom;
ReadNextAtom;
end;
end;
if CurPos.StartPos>CleanCursorPos then begin
// cursor on proc name
// -> ignore proc name and search overloaded identifier
SearchAlsoInCurContext:=false;
end;
end;
if CursorNode.Desc=ctnProcedureHead then
CursorNode:=CursorNode.Parent;
end;
if CursorNode.Desc=ctnProperty then begin
MoveCursorToNodeStart(CursorNode);
ReadNextAtom; // read 'property'
ReadNextAtom; // read property name
if CleanCursorPos<CurPos.EndPos then
SearchAlsoInCurContext:=false;
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);
if (CurPos.StartPos>=1) and (IsIdentStartChar[Src[CurPos.StartPos]]) then if (CurPos.StartPos>=1) and (IsIdentStartChar[Src[CurPos.StartPos]]) then
begin begin
// search identifier
CurPos.EndPos:=CurPos.StartPos; CurPos.EndPos:=CurPos.StartPos;
while (CurPos.EndPos<=SrcLen) and IsIdentChar[Src[CurPos.EndPos]] do while (CurPos.EndPos<=SrcLen) and IsIdentChar[Src[CurPos.EndPos]] do
inc(CurPos.EndPos); inc(CurPos.EndPos);
@ -674,12 +694,14 @@ begin
Params.SetIdentifier(Self,@Src[CurPos.StartPos],@CheckSrcIdentifier); Params.SetIdentifier(Self,@Src[CurPos.StartPos],@CheckSrcIdentifier);
Params.Flags:=[fdfSearchInParentNodes,fdfExceptionOnNotFound, Params.Flags:=[fdfSearchInParentNodes,fdfExceptionOnNotFound,
fdfTopLvlResolving]; fdfTopLvlResolving];
if not SearchAlsoInCurContext then Params.Flags:=Params.Flags
+[fdfSearchInAncestors]+fdfAllClassVisibilities;
if not DirectSearch then begin
Result:=FindDeclarationOfIdentAtCursor(Params);
end else begin
Include(Params.Flags,fdfIgnoreCurContextNode); Include(Params.Flags,fdfIgnoreCurContextNode);
if SearchInAncestors then Result:=FindIdentifierInContext(Params);
Params.Flags:=Params.Flags end;
+[fdfSearchInAncestors]+fdfAllClassVisibilities;
Result:=FindDeclarationOfIdentAtCursor(Params);
if Result then begin if Result then begin
Params.ConvertResultCleanPosToCaretPos; Params.ConvertResultCleanPosToCaretPos;
NewPos:=Params.NewPos; NewPos:=Params.NewPos;
@ -1115,6 +1137,8 @@ var
' StartPos=',ContextNode.StartPos, ' StartPos=',ContextNode.StartPos,
' EndPos=',ContextNode.EndPos, ' EndPos=',ContextNode.EndPos,
' Self=',MainFilename); ' Self=',MainFilename);
writeln(' LastCacheEntry(Pos=',LastCacheEntry^.CleanStartPos,
'-',LastCacheEntry^.CleanEndPos,')');
if (Params.NewNode<>nil) then if (Params.NewNode<>nil) then
writeln(' NewTool=',Params.NewCodeTool.MainFilename, writeln(' NewTool=',Params.NewCodeTool.MainFilename,
' NewNode=',Params.NewNode.DescAsString) ' NewNode=',Params.NewNode.DescAsString)
@ -1525,15 +1549,16 @@ begin
if Result and (not (fdfDoNotCache in Params.NewFlags)) if Result and (not (fdfDoNotCache in Params.NewFlags))
and (FirstSearchedNode<>nil) then begin and (FirstSearchedNode<>nil) then begin
// cache result // cache result
AddResultToNodeCaches(Params.Identifier,FirstSearchedNode,ContextNode, AddResultToNodeCaches(FirstSearchedNode,ContextNode,
fdfSearchForward in Params.Flags,Params,SearchRangeFlags); fdfSearchForward in Params.Flags,Params,SearchRangeFlags);
end; end;
end; end;
// if we are here, the identifier was not found // if we are here, the identifier was not found
if FirstSearchedNode<>nil then begin if FirstSearchedNode<>nil then begin
// add result to cache // add result to cache
AddResultToNodeCaches(Params.Identifier,FirstSearchedNode,LastSearchedNode, Params.NewNode:=nil;
fdfSearchForward in Params.Flags,nil,SearchRangeFlags); AddResultToNodeCaches(FirstSearchedNode,LastSearchedNode,
fdfSearchForward in Params.Flags,Params,SearchRangeFlags);
end; end;
SetResultBeforeExit(false,false); SetResultBeforeExit(false,false);
@ -3089,6 +3114,7 @@ var
if not IdentFound then begin if not IdentFound then begin
Params.Save(OldInput); Params.Save(OldInput);
try try
// build new param flags for sub identifiers
Params.Flags:=[fdfSearchInAncestors,fdfExceptionOnNotFound] Params.Flags:=[fdfSearchInAncestors,fdfExceptionOnNotFound]
+fdfAllClassVisibilities +fdfAllClassVisibilities
+(fdfGlobals*Params.Flags); +(fdfGlobals*Params.Flags);
@ -3096,9 +3122,10 @@ var
// there is no special context -> also search in parent contexts // there is no special context -> also search in parent contexts
Params.Flags:=Params.Flags Params.Flags:=Params.Flags
+[fdfSearchInParentNodes,fdfIgnoreCurContextNode]; +[fdfSearchInParentNodes,fdfIgnoreCurContextNode];
end else end else begin
// only search in special context // only search in special context
Params.ContextNode:=CurContext.Node; Params.ContextNode:=CurContext.Node;
end;
// check identifier must be checked for overloaded procs // check identifier must be checked for overloaded procs
if IsIdentifierEndOfVariable if IsIdentifierEndOfVariable
@ -4560,7 +4587,7 @@ begin
end; end;
end; end;
procedure TFindDeclarationTool.AddResultToNodeCaches(Identifier: PChar; procedure TFindDeclarationTool.AddResultToNodeCaches(
StartNode, EndNode: TCodeTreeNode; SearchedForward: boolean; StartNode, EndNode: TCodeTreeNode; SearchedForward: boolean;
Params: TFindDeclarationParams; SearchRangeFlags: TNodeCacheEntryFlags); Params: TFindDeclarationParams; SearchRangeFlags: TNodeCacheEntryFlags);
var Node: TCodeTreeNode; var Node: TCodeTreeNode;
@ -4573,15 +4600,8 @@ var Node: TCodeTreeNode;
BeVerbose: boolean; BeVerbose: boolean;
{$ENDIF} {$ENDIF}
begin begin
if (EndNode<>nil) and (EndNode.HasAsParent(StartNode)) then begin if StartNode=nil then exit;
// StartNode is parent of EndNode -> swap if Params.NewNode<>nil then begin
Node:=StartNode;
StartNode:=EndNode;
EndNode:=Node;
end;
Node:=StartNode;
LastNodeCache:=nil;
if Params<>nil then begin
// identifier found // identifier found
NewNode:=Params.NewNode; NewNode:=Params.NewNode;
NewTool:=Params.NewCodeTool; NewTool:=Params.NewCodeTool;
@ -4590,32 +4610,35 @@ begin
// identifier not found // identifier not found
NewNode:=nil; NewNode:=nil;
NewTool:=nil; NewTool:=nil;
NewCleanPos:=-1;
end; end;
// calculate search range (StartNode is on same or lower nodelvl than EndNode) // calculate search range
CleanStartPos:=StartNode.StartPos;
CleanEndPos:=StartNode.EndPos;
if EndNode<>nil then begin if EndNode<>nil then begin
if not SearchedForward then begin if SearchedForward then begin
if EndNode.StartPos<CleanStartPos then CleanStartPos:=StartNode.StartPos;
CleanStartPos:=EndNode.StartPos; CleanEndPos:=EndNode.EndPos;
end else begin end else begin
if EndNode.EndPos>CleanEndPos then CleanStartPos:=EndNode.StartPos;
CleanEndPos:=EndNode.EndPos; CleanEndPos:=StartNode.EndPos;
end; end;
end else begin end else begin
// searched till start or end of source // searched till start or end of source
if not SearchedForward then if not SearchedForward then begin
CleanStartPos:=1 CleanStartPos:=1;
else CleanEndPos:=StartNode.StartPos;
end else begin
CleanStartPos:=StartNode.StartPos;
CleanEndPos:=SrcLen+1; CleanEndPos:=SrcLen+1;
end;
end; end;
{$IFDEF ShowNodeCache} {$IFDEF ShowNodeCache}
beVerbose:=CompareSrcIdentifiers(Identifier,'FONT'); beVerbose:=CompareSrcIdentifiers(Params.Identifier,'VISIBLE');
if beVerbose then begin if beVerbose then begin
writeln('(((((((((((((((((((((((((((=================='); writeln('(((((((((((((((((((((((((((==================');
write('TFindDeclarationTool.AddResultToNodeCaches ', write('TFindDeclarationTool.AddResultToNodeCaches ',
' Ident=',GetIdentifier(Identifier)); ' Ident=',GetIdentifier(Params.Identifier));
write(' SearchedForward=',SearchedForward); write(' SearchedForward=',SearchedForward);
write(' Flags=['); write(' Flags=[');
if ncefSearchedInParents in SearchRangeFlags then write('Parents'); if ncefSearchedInParents in SearchRangeFlags then write('Parents');
@ -4631,11 +4654,15 @@ begin
write(' EndNode=nil'); write(' EndNode=nil');
writeln(''); writeln('');
writeln(' StartNode(',StartNode.StartPos,'-',StartNode.EndPos,')');
if EndNode<>nil then
writeln(' EndNode(',EndNode.StartPos,'-',EndNode.EndPos,')');
writeln(' Self=',MainFilename); writeln(' Self=',MainFilename);
if Params<>nil then begin if NewNode<>nil then begin
writeln(' NewNode=',Params.NewNode.DescAsString, writeln(' NewNode=',NewNode.DescAsString,
' NewTool=',Params.NewCodeTool.MainFilename); ' NewTool=',NewTool.MainFilename);
end else begin end else begin
writeln(' NOT FOUND'); writeln(' NOT FOUND');
end; end;
@ -4644,6 +4671,19 @@ begin
writeln(' CleanEndPos=',CleanEndPos,' "',copy(Src,CleanEndPos-70,70),'"'); writeln(' CleanEndPos=',CleanEndPos,' "',copy(Src,CleanEndPos-70,70),'"');
end; end;
{$ENDIF} {$ENDIF}
LastNodeCache:=nil;
// start with parent of deepest node and end parent of highest
Node:=StartNode;
if (EndNode<>nil) then begin
if (EndNode.GetLevel>StartNode.GetLevel) then begin
Node:=EndNode;
EndNode:=StartNode.Parent;
end else begin
EndNode:=EndNode.Parent;
end;
end else
EndNode:=StartNode.Parent;
Node:=Node.Parent;
while (Node<>nil) do begin while (Node<>nil) do begin
if (Node.Desc in AllNodeCacheDescs) then begin if (Node.Desc in AllNodeCacheDescs) then begin
if (Node.Cache=nil) then if (Node.Cache=nil) then
@ -4656,7 +4696,8 @@ begin
CurNodeCache.WriteDebugReport(' BEFORE NODECACHE REPORT: '); CurNodeCache.WriteDebugReport(' BEFORE NODECACHE REPORT: ');
end; end;
{$ENDIF} {$ENDIF}
CurNodeCache.Add(Identifier,CleanStartPos,CleanEndPos, CurNodeCache.Add(Params.Identifier,
CleanStartPos,CleanEndPos,
NewNode,NewTool,NewCleanPos,SearchRangeFlags); NewNode,NewTool,NewCleanPos,SearchRangeFlags);
{$IFDEF ShowNodeCache} {$IFDEF ShowNodeCache}
if BeVerbose then begin if BeVerbose then begin
@ -4668,7 +4709,7 @@ begin
end; end;
end; end;
Node:=Node.Parent; Node:=Node.Parent;
if (EndNode<>nil) and (Node=EndNode.Parent) then break; if (EndNode=Node) then break;
end; end;
{$IFDEF ShowNodeCache} {$IFDEF ShowNodeCache}
if BeVerbose then begin if BeVerbose then begin

View File

@ -254,17 +254,16 @@ const
var CursorNode, ClassNode, ProcNode, StartNode, TypeSectionNode, var CursorNode, ClassNode, ProcNode, StartNode, TypeSectionNode,
ANode: TCodeTreeNode; ANode: TCodeTreeNode;
CleanCursorPos, LineStart, LineEnd, FirstAtomStart, LastAtomEnd, CleanCursorPos, LineStart, LineEnd, FirstAtomStart, LastAtomEnd: integer;
DiffTxtPos: integer;
SearchedClassname, SearchedProcName, SearchedParamList: string; SearchedClassname, SearchedProcName, SearchedParamList: string;
SearchForNodes, SearchInNodes: TAVLTree; SearchForNodes, SearchInNodes: TAVLTree;
DiffNode, BodyAVLNode, DefAVLNode: TAVLTreeNode; BodyAVLNode, DefAVLNode: TAVLTreeNode;
begin begin
Result:=false; Result:=false;
NewPos:=CursorPos; NewPos:=CursorPos;
// build code tree // build code tree
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
writeln('TMethodJumpingCodeTool.FindJumpPoint A CursorPos=',CursorPos.X,',',CursorPos.Y); writeln('TMethodJumpingCodeTool.FindJumpPoint A CursorPos=',CursorPos.X,',',CursorPos.Y);
{$ENDIF} {$ENDIF}
BuildTreeAndGetCleanPos(trAll,CursorPos,CleanCursorPos); BuildTreeAndGetCleanPos(trAll,CursorPos,CleanCursorPos);
GetLineInfo(CleanCursorPos,LineStart,LineEnd,FirstAtomStart,LastAtomEnd); GetLineInfo(CleanCursorPos,LineStart,LineEnd,FirstAtomStart,LastAtomEnd);