From ce24bd7399d50a0791842d3d66cb7de312392da4 Mon Sep 17 00:00:00 2001 From: lazarus Date: Tue, 15 Jan 2002 17:28:40 +0000 Subject: [PATCH] MG: find declaration for pointers, with statements, forward classes, as operator git-svn-id: trunk@599 - --- components/codetools/codecompletiontool.pas | 8 +- components/codetools/customcodetool.pas | 10 +- components/codetools/finddeclarationtool.pas | 352 +++++++++++++++---- components/codetools/methodjumptool.pas | 6 +- components/codetools/pascalparsertool.pas | 4 + 5 files changed, 295 insertions(+), 85 deletions(-) diff --git a/components/codetools/codecompletiontool.pas b/components/codetools/codecompletiontool.pas index 15dca59516..9547bc6d40 100644 --- a/components/codetools/codecompletiontool.pas +++ b/components/codetools/codecompletiontool.pas @@ -940,9 +940,7 @@ begin // in a class or in a forward proc? BuildTreeAndGetCleanPos(false,CursorPos, CleanCursorPos); // find CodeTreeNode at cursor - CursorNode:=FindDeepestNodeAtPos(CleanCursorPos); - if CursorNode=nil then - RaiseException('no valid node found at cursor'); + CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true); ASourceChangeCache:=SourceChangeCache; SourceChangeCache.MainScanner:=Scanner; {$IFDEF CTDEBUG} @@ -1032,9 +1030,7 @@ writeln('TCodeCompletionCodeTool.CompleteCode Jump to new proc body ... '); if (Dummy<>0) and (Dummy<>-1) then RaiseException('cursor pos outside of code'); // find CodeTreeNode at cursor - CursorNode:=FindDeepestNodeAtPos(CleanCursorPos); - if CursorNode=nil then - RaiseException('no valid node found at cursor'); + CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true); ClassNode:=CursorNode; while (ClassNode<>nil) and (ClassNode.Desc<>ctnClass) do diff --git a/components/codetools/customcodetool.pas b/components/codetools/customcodetool.pas index 04e6a226ef..3d06d784c3 100644 --- a/components/codetools/customcodetool.pas +++ b/components/codetools/customcodetool.pas @@ -76,7 +76,8 @@ type property Scanner: TLinkScanner read FScanner write SetScanner; - function FindDeepestNodeAtPos(P: integer): TCodeTreeNode; + function FindDeepestNodeAtPos(P: integer; + ExceptionOnNotFound: boolean): TCodeTreeNode; function CaretToCleanPos(Caret: TCodeXYPosition; var CleanPos: integer): integer; // 0=valid CleanPos //-1=CursorPos was skipped, CleanPos between two links @@ -1078,7 +1079,8 @@ begin WriteSubTree(Tree.Root,' '); end; -function TCustomCodeTool.FindDeepestNodeAtPos(P: integer): TCodeTreeNode; +function TCustomCodeTool.FindDeepestNodeAtPos(P: integer; + ExceptionOnNotFound: boolean): TCodeTreeNode; function SearchInNode(ANode: TCodeTreeNode): TCodeTreeNode; begin @@ -1103,6 +1105,10 @@ function TCustomCodeTool.FindDeepestNodeAtPos(P: integer): TCodeTreeNode; // TCustomCodeTool.FindDeepestNodeAtPos begin Result:=SearchInNode(Tree.Root); + if (Result=nil) and ExceptionOnNotFound then begin + MoveCursorToCleanPos(P); + RaiseException('no node found at cursor'); + end; end; function TCustomCodeTool.CaretToCleanPos(Caret: TCodeXYPosition; diff --git a/components/codetools/finddeclarationtool.pas b/components/codetools/finddeclarationtool.pas index 21e0ef559e..09d073583b 100644 --- a/components/codetools/finddeclarationtool.pas +++ b/components/codetools/finddeclarationtool.pas @@ -63,7 +63,7 @@ interface {$I codetools.inc} -{$DEFINE CTDEBUG} +{ $DEFINE CTDEBUG} uses {$IFDEF MEM_CHECK} @@ -77,8 +77,16 @@ type // searchpath delimiter is semicolon TOnGetSearchPath = function(Sender: TObject): string; - TFindDeclarationFlag = (fdfSearchInParentNodes,fdfSearchInAncestors, - fdfIgnoreCurContextNode, + TFindDeclarationFlag = ( + fdfSearchInParentNodes, // if identifier not found in current context, + // proceed in prior nodes on same lvl and parents + fdfSearchInAncestors, // if context is a class, search also in + // ancestors/interfaces + fdfIgnoreCurContextNode,// skip context and proceed in prior/parent context + fdfExceptionOnNotFound, // raise exception if identifier not found + fdfIgnoreUsedUnits, // stay in current source + fdfSearchForward, // instead of searching in prior nodes, search in + // next nodes (successors) fdfClassPublished,fdfClassPublic,fdfClassProtected,fdfClassPrivate); TFindDeclarationFlags = set of TFindDeclarationFlag; @@ -114,6 +122,11 @@ type TFindDeclarationTool = class(TPascalParserTool) private FOnGetUnitSourceSearchPath: TOnGetSearchPath; + {$IFDEF CTDEBUG} + DebugPrefix: string; + procedure IncPrefix; + procedure DecPrefix; + {$ENDIF} function FindDeclarationInUsesSection(UsesNode: TCodeTreeNode; CleanPos: integer; var NewPos: TCodeXYPosition; var NewTopLine: integer): boolean; @@ -128,8 +141,12 @@ type Node: TCodeTreeNode): TCodeTreeNode; function FindIdentifierInProcContext(ProcContextNode: TCodeTreeNode; Params: TFindDeclarationParams): boolean; + function FindIdentifierInWithVarContext(WithVarNode: TCodeTreeNode; + Params: TFindDeclarationParams): boolean; function FindClassOfMethod(ProcNode: TCodeTreeNode; Params: TFindDeclarationParams; FindClassContext: boolean): boolean; + function FindForwardIdentifier(Params: TFindDeclarationParams; + var IsForward: boolean): boolean; public function FindDeclaration(CursorPos: TCodeXYPosition; var NewPos: TCodeXYPosition; var NewTopLine: integer): boolean; @@ -146,6 +163,7 @@ implementation const fdfAllClassVisibilities = [fdfClassPublished,fdfClassPublic,fdfClassProtected, fdfClassPrivate]; + fdfGlobals = [fdfExceptionOnNotFound, fdfIgnoreUsedUnits]; { TFindDeclarationTool } @@ -158,16 +176,14 @@ begin Result:=false; // build code tree {$IFDEF CTDEBUG} -writeln('TFindDeclarationTool.FindDeclaration A CursorPos=',CursorPos.X,',',CursorPos.Y); +writeln(DebugPrefix,'TFindDeclarationTool.FindDeclaration A CursorPos=',CursorPos.X,',',CursorPos.Y); {$ENDIF} BuildTreeAndGetCleanPos(false,CursorPos,CleanCursorPos); {$IFDEF CTDEBUG} -writeln('TFindDeclarationTool.FindDeclaration C CleanCursorPos=',CleanCursorPos); +writeln(DebugPrefix,'TFindDeclarationTool.FindDeclaration C CleanCursorPos=',CleanCursorPos); {$ENDIF} // find CodeTreeNode at cursor - CursorNode:=FindDeepestNodeAtPos(CleanCursorPos); - if CursorNode=nil then - RaiseException('no node found at cursor'); + CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true); if IsIncludeDirectiveAtPos(CleanCursorPos,CursorNode.StartPos,NewPos.Code) then begin NewPos.X:=1; @@ -193,10 +209,13 @@ writeln('TFindDeclarationTool.FindDeclaration D CursorNode=',NodeDescriptionAsSt if ClassNode.SubDesc<>ctnsForwardDeclaration then begin // parse class and build CodeTreeNodes for all properties/methods BuildSubTreeForClass(ClassNode); + CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true); end; end; - if CursorNode.Desc=ctnBeginBlock then + if CursorNode.Desc=ctnBeginBlock then begin BuildSubTreeForBeginBlock(CursorNode); + CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true); + end; MoveCursorToCleanPos(CleanCursorPos); while (CurPos.StartPos>1) and (IsIdentChar[Src[CurPos.StartPos-1]]) do dec(CurPos.StartPos); @@ -211,7 +230,8 @@ writeln('TFindDeclarationTool.FindDeclaration D CursorNode=',NodeDescriptionAsSt Params.ContextNode:=CursorNode; Params.IdentifierStartPos:=CurPos.StartPos; Params.IdentifierEndPos:=CurPos.EndPos; - Params.Flags:=[fdfSearchInAncestors,fdfSearchInParentNodes]; + Params.Flags:=[fdfSearchInAncestors,fdfSearchInParentNodes, + fdfExceptionOnNotFound]; Result:=FindDeclarationOfIdentifier(Params); if Result then begin Params.ConvertResultCleanPosToCaretPos; @@ -506,9 +526,17 @@ writeln('[TFindDeclarationTool.FindDeclarationOfIdentifier] Identifier=', MoveCursorToCleanPos(Params.IdentifierStartPos); OldContextNode:=Params.ContextNode; NewContextNode:=FindContextNodeAtCursor(Params); - Params.Flags:=[fdfSearchInAncestors]+fdfAllClassVisibilities; + Params.Flags:=[fdfSearchInAncestors,fdfIgnoreCurContextNode] + +fdfAllClassVisibilities+(fdfGlobals*Params.Flags); if NewContextNode=OldContextNode then Include(Params.Flags,fdfSearchInParentNodes); + if (OldContextNode.Desc=ctnTypeDefinition) + and (OldContextNode.FirstChild<>nil) + and (OldContextNode.FirstChild.Desc=ctnClass) + and (OldContextNode.FirstChild.SubDesc=ctnsForwardDeclaration) + then + Include(Params.Flags,fdfSearchForward); + Params.ContextNode:=NewContextNode; Result:=FindIdentifierInContext(Params); end; @@ -526,6 +554,7 @@ function TFindDeclarationTool.FindIdentifierInContext( true, if NewPos+NewTopLine valid } var LastContextNode, StartContextNode, ContextNode: TCodeTreeNode; + IsForward: boolean; begin ContextNode:=Params.ContextNode; StartContextNode:=ContextNode; @@ -535,7 +564,7 @@ begin {$IFDEF CTDEBUG} writeln('[TFindDeclarationTool.FindIdentifierInContext] A Ident=', copy(Src,Params.IdentifierStartPos,Params.IdentifierEndPos-Params.IdentifierStartPos), -' Context=',ContextNode.DescAsString, +' Context=',ContextNode.DescAsString,' ', ' ParentsAllowed=',fdfSearchInParentNodes in Params.Flags, ' AncestorsAllowed=',fdfSearchInAncestors in Params.Flags ); @@ -551,8 +580,12 @@ if (ContextNode.Desc=ctnClass) then ctnClassPublic, ctnClassPrivate, ctnClassProtected, ctnClassPublished, ctnClass, ctnRecordType, ctnRecordCase, ctnRecordVariant: - if ContextNode.LastChild<>nil then - ContextNode:=ContextNode.LastChild; + if (ContextNode.LastChild<>nil) then begin + if not (fdfSearchForward in Params.Flags) then + ContextNode:=ContextNode.LastChild + else + ContextNode:=ContextNode.FirstChild; + end; ctnTypeDefinition, ctnVarDefinition, ctnConstDefinition, ctnEnumType: begin @@ -618,9 +651,16 @@ writeln(' Definition Identifier found=',copy(Src,ContextNode.StartPos,Params.Id ctnWithVariable: begin + Result:=FindIdentifierInWithVarContext(ContextNode,Params); + if Result then exit; + end; - // ToDo: - + ctnPointerType: + begin + // pointer types can be forward definitions + Params.ContextNode:=ContextNode.Parent; + Result:=FindForwardIdentifier(Params,IsForward); + exit; end; @@ -653,10 +693,17 @@ writeln('[TFindDeclarationTool.FindIdentifierInContext] no prior node accessible repeat // search for prior node {$IFDEF CTDEBUG} -writeln('[TFindDeclarationTool.FindIdentifierInContext] Searching prior node of ',ContextNode.DescAsString); +//writeln('[TFindDeclarationTool.FindIdentifierInContext] Searching prior node of ',ContextNode.DescAsString); {$ENDIF} - if ContextNode.PriorBrother<>nil then begin - ContextNode:=ContextNode.PriorBrother; + if ((not (fdfSearchForward in Params.Flags)) + and (ContextNode.PriorBrother<>nil)) + or ((fdfSearchForward in Params.Flags) + and (ContextNode.NextBrother<>nil)) then + begin + if not (fdfSearchForward in Params.Flags) then + ContextNode:=ContextNode.PriorBrother + else + ContextNode:=ContextNode.NextBrother; {$IFDEF CTDEBUG} writeln('[TFindDeclarationTool.FindIdentifierInContext] Searching in PriorBrother ContextNode=',ContextNode.DescAsString); {$ENDIF} @@ -714,6 +761,11 @@ writeln('[TFindDeclarationTool.FindIdentifierInContext] Searching in Parent Con end else begin // DeepestNode=nil -> ignore end; + if fdfExceptionOnNotFound in Params.Flags then begin + MoveCursorToCleanPos(Params.IdentifierStartPos); + RaiseException('Identifier not found '+copy(Src,Params.IdentifierStartPos, + Params.IdentifierEndPos-Params.IdentifierStartPos)); + end; end; function TFindDeclarationTool.FindEnumInContext( @@ -733,6 +785,8 @@ begin if Params.ContextNode=nil then exit; OldContextNode:=Params.ContextNode; try + if Params.ContextNode.Desc=ctnClass then + BuildSubTreeForClass(Params.ContextNode); Params.ContextNode:=Params.ContextNode.FirstChild; while Params.ContextNode<>nil do begin if (Params.ContextNode.Desc in [ctnEnumType]) @@ -838,6 +892,7 @@ begin exit; end; Result:=FindContextNodeAtCursor(Params); + if Result=nil then exit; // coming back the left side has been parsed and // now the parsing goes from left to right @@ -857,11 +912,11 @@ writeln(''); atIdentifier: begin + // for example 'AnObject[3]' if not (NextAtomType in [atSpace,atPoint,atUp,atAS,atRoundBracketOpen, atEdgedBracketOpen]) then begin MoveCursorToCleanPos(NextAtom.StartPos); - ReadNextAtom; RaiseException('syntax error: "'+GetAtom+'" found'); end; if (Result=Params.ContextNode) @@ -880,9 +935,13 @@ writeln(''); ProcNode:=ProcNode.Parent; end; end; + // find identifier Params.Save(OldInput); try - Params.Flags:=[fdfSearchInAncestors]+fdfAllClassVisibilities; + Params.Flags:=[fdfSearchInAncestors,fdfIgnoreCurContextNode] + +fdfAllClassVisibilities + +(fdfGlobals*Params.Flags) + +[fdfExceptionOnNotFound]; //writeln(' ',Result=Params.ContextNode,' ',Result.DescAsString,',',Params.ContextNode.DescAsString); if Result=Params.ContextNode then begin // there is no special context -> also search in parent contexts @@ -891,10 +950,8 @@ writeln(''); Params.ContextNode:=Result; Params.IdentifierStartPos:=CurAtom.StartPos; Params.IdentifierEndPos:=CurAtom.EndPos; - if FindIdentifierInContext(Params) then - Result:=Params.NewNode - else - Result:=nil; + FindIdentifierInContext(Params); + Result:=Params.NewNode; finally Params.Load(OldInput); end; @@ -902,18 +959,66 @@ writeln(''); atPoint: begin + // for example 'A.B' if (not (NextAtomType in [atSpace,atIdentifier])) then begin MoveCursorToCleanPos(NextAtom.StartPos); - ReadNextAtom; RaiseException('syntax error: identifier expected, but ' +GetAtom+' found'); end; + // there is nothing special to do here, because the '.' will only change + // from an identifier to its type context. But this is always done. end; - // ToDo: atAS, atINHERITED, atUp, atRoundBracketClose, atEdgedBracketClose + atAS: + begin + // for example 'A as B' + if (not (NextAtomType in [atSpace,atIdentifier])) then begin + MoveCursorToCleanPos(NextAtom.StartPos); + RaiseException('syntax error: identifier expected, but ' + +GetAtom+' found'); + end; + // 'as' is a type cast, so the left side is irrelevant + // -> context is default context + Result:=Params.ContextNode; + end; + + atUP: + begin + // for example: + // 1. 'PInt = ^integer' pointer type + // 2. a^ dereferencing + if Result<>Params.ContextNode then begin + // left side of expression has defined a special context + // => this '^' is a dereference + if (not (NextAtomType in [atSpace,atPoint,atAS,atUP])) then begin + MoveCursorToCleanPos(NextAtom.StartPos); + RaiseException('syntax error: . expected, but '+GetAtom+' found'); + end; + if Result.Desc<>ctnPointerType then begin + MoveCursorToCleanPos(CurAtom.StartPos); + RaiseException('illegal qualifier ^'); + end; + Result:=Result.FirstChild; + end else if NodeHasParentOfType(Result,ctnPointerType) then begin + // this is a pointer type definition + // -> the default context is ok + end; + end; + + + // ToDo: atINHERITED, atRoundBracketClose, atEdgedBracketClose else - Result:=Params.ContextNode; + begin + if (not (NextAtomType in [atSpace,atIdentifier,atRoundBracketOpen, + atEdgedBracketOpen])) then + begin + MoveCursorToCleanPos(NextAtom.StartPos); + RaiseException('syntax error: identifier expected, but ' + +GetAtom+' found'); + end; + Result:=Params.ContextNode; + end; end; // try to get the base type of the found context @@ -931,6 +1036,7 @@ end; function TFindDeclarationTool.FindBaseTypeOfNode(Params: TFindDeclarationParams; Node: TCodeTreeNode): TCodeTreeNode; var OldInput: TFindDeclarationInput; + ClassIdentNode: TCodeTreeNode; begin Result:=Node; while (Result<>nil) do begin @@ -941,9 +1047,31 @@ begin if (Result.Desc=ctnClass) and (Result.SubDesc=ctnsForwardDeclaration) then begin // search the real class - - // ToDo - + ClassIdentNode:=Result.Parent; + if (ClassIdentNode=nil) or (not (ClassIdentNode.Desc=ctnTypeDefinition)) + then begin + MoveCursorToCleanPos(Result.StartPos); + RaiseException('[TFindDeclarationTool.FindBaseTypeOfNode] ' + +'forward class node without name'); + end; + Params.Save(OldInput); + try + Params.IdentifierStartPos:=ClassIdentNode.StartPos; + Params.IdentifierEndPos:=ClassIdentNode.EndPos; + Params.Flags:=[fdfSearchInParentNodes,fdfSearchForward] + +(fdfGlobals*Params.Flags) + +[fdfExceptionOnNotFound]; + Params.ContextNode:=ClassIdentNode; + FindIdentifierInContext(Params); + if Params.NewNode.Desc<>ctnTypeDefinition then begin + MoveCursorToCleanPos(Result.StartPos); + RaiseException('Forward class definition not resolved: ' + +copy(Src,ClassIdentNode.StartPos, + ClassIdentNode.EndPos-ClassIdentNode.StartPos)); + end; + finally + Params.Load(OldInput); + end; end else if (Result.Desc=ctnTypeType) then begin // a TypeType is for example 'MyInt = type integer;' @@ -959,7 +1087,8 @@ begin try Params.IdentifierStartPos:=Result.StartPos; Params.IdentifierEndPos:=Result.EndPos; - Params.Flags:=[fdfSearchInParentNodes]; + Params.Flags:=[fdfSearchInParentNodes]+(fdfGlobals*Params.Flags) + -[fdfExceptionOnNotFound]; Params.ContextNode:=Result.Parent; if FindIdentifierInContext(Params) then begin if Result.HasAsParent(Params.NewNode) then @@ -1010,37 +1139,35 @@ begin // 1. search the class Params.Save(OldInput); try - Params.Flags:=[fdfIgnoreCurContextNode,fdfSearchInParentNodes]; + Params.Flags:=[fdfIgnoreCurContextNode,fdfSearchInParentNodes] + +(fdfGlobals*Params.Flags) + +[fdfExceptionOnNotFound]; Params.ContextNode:=ProcContextNode; Params.IdentifierStartPos:=ClassNameAtom.StartPos; Params.IdentifierEndPos:=ClassNameAtom.EndPos; {$IFDEF CTDEBUG} writeln(' searching class of method class="',copy(Src,ClassNameAtom.StartPos,ClassNameAtom.EndPos-ClassNameAtom.StartPos),'"'); {$ENDIF} - if FindIdentifierInContext(Params) then begin - ClassContextNode:=FindBaseTypeOfNode(Params,Params.NewNode); - if (ClassContextNode=nil) - or (ClassContextNode.Desc<>ctnClass) then begin - MoveCursorToCleanPos(ClassNameAtom.StartPos); - RaiseException('class identifier expected'); - end; - // class of method found - BuildSubTreeForClass(ClassContextNode); - // class context found -> search identifier - Params.Load(OldInput); - Params.Flags:=[fdfSearchInAncestors]+fdfAllClassVisibilities; - Params.ContextNode:=ClassContextNode; + FindIdentifierInContext(Params); + ClassContextNode:=FindBaseTypeOfNode(Params,Params.NewNode); + if (ClassContextNode=nil) + or (ClassContextNode.Desc<>ctnClass) then begin + MoveCursorToCleanPos(ClassNameAtom.StartPos); + RaiseException('class identifier expected'); + end; + // class of method found + BuildSubTreeForClass(ClassContextNode); + // class context found -> search identifier + Params.Load(OldInput); + Params.Flags:=[fdfSearchInAncestors]+fdfAllClassVisibilities + +(fdfGlobals*Params.Flags) + -[fdfExceptionOnNotFound]; + Params.ContextNode:=ClassContextNode; {$IFDEF CTDEBUG} writeln(' searching identifier in class of method'); {$ENDIF} - Result:=FindIdentifierInContext(Params); - if Result then exit; - end else begin - // class not found -> cancel the search - MoveCursorToCleanPos(ClassNameAtom.StartPos); - RaiseException('class not found'); - exit; - end; + Result:=FindIdentifierInContext(Params); + if Result then exit; finally Params.Load(OldInput); end; @@ -1080,33 +1207,29 @@ writeln('[TFindDeclarationTool.FindClassOfMethod] A'); // -> search the class Params.Save(OldInput); try - Params.Flags:=[fdfIgnoreCurContextNode,fdfSearchInParentNodes]; + Params.Flags:=[fdfIgnoreCurContextNode,fdfSearchInParentNodes] + +(fdfGlobals*Params.Flags) + -[fdfExceptionOnNotFound]; Params.ContextNode:=ProcNode; Params.IdentifierStartPos:=ClassNameAtom.StartPos; Params.IdentifierEndPos:=ClassNameAtom.EndPos; {$IFDEF CTDEBUG} writeln(' searching class of method class="',copy(Src,ClassNameAtom.StartPos,ClassNameAtom.EndPos-ClassNameAtom.StartPos),'"'); {$ENDIF} - if FindIdentifierInContext(Params) then begin - if FindClassContext then begin - // parse class and return class node - Params.NewNode:=FindBaseTypeOfNode(Params,Params.NewNode); - if (Params.NewNode=nil) - or (Params.NewNode.Desc<>ctnClass) then begin - MoveCursorToCleanPos(ClassNameAtom.StartPos); - RaiseException('class identifier expected'); - end; - // class of method found - // parse class and return class node - BuildSubTreeForClass(Params.NewNode); + FindIdentifierInContext(Params); + if FindClassContext then begin + // parse class and return class node + Params.NewNode:=FindBaseTypeOfNode(Params,Params.NewNode); + if (Params.NewNode=nil) + or (Params.NewNode.Desc<>ctnClass) then begin + MoveCursorToCleanPos(ClassNameAtom.StartPos); + RaiseException('class identifier expected'); end; - Result:=true; - end else begin - // class not found -> cancel the search - MoveCursorToCleanPos(ClassNameAtom.StartPos); - RaiseException('class not found'); - exit; + // class of method found + // parse class and return class node + BuildSubTreeForClass(Params.NewNode); end; + Result:=true; finally Params.Load(OldInput); end; @@ -1115,6 +1238,89 @@ writeln(' searching class of method class="',copy(Src,ClassNameAtom.StartPos, end; end; +function TFindDeclarationTool.FindForwardIdentifier( + Params: TFindDeclarationParams; var IsForward: boolean): boolean; +{ first search the identifier in the normal way via FindIdentifierInContext + then search the other direction } +var + OldInput: TFindDeclarationInput; +begin + Params.Save(OldInput); + try + Exclude(Params.Flags,fdfExceptionOnNotFound); + Result:=FindIdentifierInContext(Params); + if not Result then begin + Params.Load(OldInput); + Include(Params.Flags,fdfSearchForward); + Result:=FindIdentifierInContext(Params); + IsForward:=true; + end else + IsForward:=false; + finally + Params.Load(OldInput); + end; +end; + +function TFindDeclarationTool.FindIdentifierInWithVarContext( + WithVarNode: TCodeTreeNode; Params: TFindDeclarationParams): boolean; +{ this function is internally used by FindIdentifierInContext +} +var + WithVarContextNode: TCodeTreeNode; + OldInput: TFindDeclarationInput; +begin +{$IFDEF CTDEBUG} +writeln('[TFindDeclarationTool.FindIdentifierInWithVarContext] ', +copy(Src,Params.IdentifierStartPos,Params.IdentifierEndPos-Params.IdentifierStartPos) +); +{$ENDIF} + Result:=false; + // find the base type of the with variable + // move cursor to end of with-expression + if (WithVarNode.FirstChild<>nil) then begin + // this is the last with-variable + MoveCursorToCleanPos(WithVarNode.FirstChild.StartPos); + ReadPriorAtom; // read 'do' + CurPos.EndPos:=CurPos.StartPos; // make the 'do' unread, + // because 'do' is not part of the expr + end else begin + // this is not the last with variable, so the expr end is equal to node end + MoveCursorToCleanPos(WithVarNode.EndPos); + end; + Params.Save(OldInput); + try + Params.ContextNode:=WithVarNode; + Include(Params.Flags,fdfExceptionOnNotFound); + WithVarContextNode:=FindContextNodeAtCursor(Params); + if (WithVarContextNode=nil) or (WithVarContextNode=OldInput.ContextNode) + or (not (WithVarContextNode.Desc in [ctnClass,ctnRecordType])) then begin + MoveCursorToCleanPos(WithVarNode.StartPos); + RaiseException('expression type must be class or record type'); + end; + // search identifier in with context + Params.Load(OldInput); + Exclude(Params.Flags,fdfExceptionOnNotFound); + Params.ContextNode:=WithVarContextNode; + if FindIdentifierInContext(Params) then begin + // identifier found in with context + Result:=true; + end; + finally + Params.Load(OldInput); + end; +end; + +{$IFDEF CTDEBUG} +procedure TFindDeclarationTool.DecPrefix; +begin + DebugPrefix:=copy(DebugPrefix,1,length(DebugPrefix)-2); +end; + +procedure TFindDeclarationTool.IncPrefix; +begin + DebugPrefix:=DebugPrefix+' '; +end; +{$ENDIF} { TFindDeclarationParams } diff --git a/components/codetools/methodjumptool.pas b/components/codetools/methodjumptool.pas index 78e5e6cb65..41f08b8774 100644 --- a/components/codetools/methodjumptool.pas +++ b/components/codetools/methodjumptool.pas @@ -180,9 +180,7 @@ writeln('TMethodJumpingCodeTool.FindJumpPoint B'); if CleanCursorPos=LastAtomEnd then CleanCursorPos:=LastAtomEnd-1; // find CodeTreeNode at cursor - CursorNode:=FindDeepestNodeAtPos(CleanCursorPos); - if CursorNode=nil then - RaiseException('no node found at cursor'); + CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true); {$IFDEF CTDEBUG} writeln('TMethodJumpingCodeTool.FindJumpPoint C ',NodeDescriptionAsString(CursorNode.Desc)); {$ENDIF} @@ -208,7 +206,7 @@ writeln('TMethodJumpingCodeTool.FindJumpPoint D ',CleanCursorPos,', |',copy(Src, and (TypeSectionNode.Parent.Desc=ctnTypeSection) then TypeSectionNode:=TypeSectionNode.Parent; // search the method node under the cursor - CursorNode:=FindDeepestNodeAtPos(CleanCursorPos); + CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,false); if (CursorNode=nil) or (not (CursorNode.Desc in [ctnProcedureHead,ctnProcedure])) then exit; diff --git a/components/codetools/pascalparsertool.pas b/components/codetools/pascalparsertool.pas index e29eb94832..133eedf14b 100644 --- a/components/codetools/pascalparsertool.pas +++ b/components/codetools/pascalparsertool.pas @@ -609,6 +609,10 @@ begin if BeginNode=nil then RaiseException( 'TPascalParserTool.BuildSubTreeForBeginBlock: BeginNode=nil'); + if BeginNode.Desc<>ctnBeginBlock then + RaiseException( + 'TPascalParserTool.BuildSubTreeForBeginBlock: BeginNode.Desc=' + +BeginNode.DescAsString); if BeginNode.FirstChild<>nil then // block already parsed exit;