codetools: fixed crash on searching in used namespaces

This commit is contained in:
mattias 2025-01-01 17:16:29 +01:00
parent 065994a7d1
commit d6fd8ec102
3 changed files with 48 additions and 46 deletions

View File

@ -9740,7 +9740,10 @@ var
function ResolveUseUnit(StartUseUnitNode: TCodeTreeNode): TCodeTreeNode; function ResolveUseUnit(StartUseUnitNode: TCodeTreeNode): TCodeTreeNode;
// IsStart=true, NextAtomType=vatPoint, // IsStart=true, NextAtomType=vatPoint,
// StartUseUnitNameNode.Desc=ctnUseUnit // StartUseUnitNameNode.Desc=ctnUseUnit
// -> Find the longest namespaced used unit (ctnUseUnitNamespace,ctnUseUnitClearName) // The first dotted identifier matches a name in one of the uses sections.
// If any uses section or the source name has namespaces the longest fitting wins.
// Note: the uses section names hide all identifiers in the used unit interfaces.
// -> Find the longest (namespaced) used unit (ctnUseUnitNamespace,ctnUseUnitClearName)
// or the source name (ctnIdentifier), that fits the start of the // or the source name (ctnIdentifier), that fits the start of the
// current identifier a.b.c... // current identifier a.b.c...
// //
@ -9761,37 +9764,24 @@ var
var var
UseUnitNode, Node, BestNode: TCodeTreeNode; UseUnitNode, Node, BestNode: TCodeTreeNode;
HasNamespace: Boolean; Level, BestLevel: Integer;
Count, Level, BestLevel: Integer;
p: PChar; p: PChar;
DottedIdentifier: String; DottedIdentifier: String;
begin begin
Result:=StartUseUnitNode.FirstChild; Result:=StartUseUnitNode.FirstChild;
//debugln(['ResolveUsenit START ',NextAtomType,' ',StartUseUnitNode.DescAsString,' "',GetIdentifier(@Src[CurAtom.StartPos]),'"']); if not HasNameSpaces then exit;
// find all candidates
Count:=0;
HasNamespace:=false;
UseUnitNode:=StartUseUnitNode;
repeat
if (UseUnitNode.FirstChild<>nil)
and CompareSrcIdentifiers(CurAtom.StartPos,UseUnitNode.StartPos) then begin
// found candidate
inc(Count);
//debugln(['ResolveUsenit candidate found']);
if UseUnitNode.FirstChild.Desc=ctnUseUnitNamespace then begin
HasNamespace:=true;
end;
end;
UseUnitNode:=GetPrevUseUnit(UseUnitNode);
until UseUnitNode=nil;
//debugln(['ResolveUsenit CandidateCount=',Count,' HasNamespace=',HasNamespace]);
if not HasNamespace then exit;
DottedIdentifier:=GetIdentifier(@Src[CurAtom.StartPos]);
//debugln(['ResolveUseUnit START ',NextAtomType,' ',StartUseUnitNode.DescAsString,' "',GetIdentifier(@Src[CurAtom.StartPos]),'" Result=',Result.DescAsString]);
// find all candidates
BestNode:=nil;
BestLevel:=0;
// multiple uses start with this identifier -> collect candidates // multiple uses start with this identifier -> collect candidates
//debugln(['ResolveUsenit collect candidates ...']); //debugln(['ResolveUseUnit collect candidates ...']);
// read a.b.c... // read a.b.c...
DottedIdentifier:=GetIdentifier(@Src[CurAtom.StartPos]);
MoveCursorToCleanPos(NextAtom.EndPos); MoveCursorToCleanPos(NextAtom.EndPos);
Level:=1; Level:=1;
repeat repeat
@ -9801,12 +9791,10 @@ var
DottedIdentifier:=DottedIdentifier+'.'+GetAtom; DottedIdentifier:=DottedIdentifier+'.'+GetAtom;
ReadNextAtom; ReadNextAtom;
until CurPos.Flag<>cafPoint; until CurPos.Flag<>cafPoint;
//debugln(['ResolveUsenit DottedIdentifier="',DottedIdentifier,'"']); //debugln(['ResolveUseUnit DottedIdentifier="',DottedIdentifier,'"']);
// find longest dotted unit name in uses and source name // find longest dotted unit name in uses and source name
UseUnitNode:=StartUseUnitNode; UseUnitNode:=StartUseUnitNode;
BestNode:=nil;
BestLevel:=0;
repeat repeat
Node:=UseUnitNode.FirstChild; // ctnUseUnitNamespace or ctnUseUnitClearName Node:=UseUnitNode.FirstChild; // ctnUseUnitNamespace or ctnUseUnitClearName
UseUnitNode:=GetPrevUseUnit(UseUnitNode); UseUnitNode:=GetPrevUseUnit(UseUnitNode);
@ -9892,7 +9880,10 @@ var
end; end;
Result:=BestNode; Result:=BestNode;
if Result=nil then exit; if Result=nil then begin
// ToDo: search in used interfaces
exit(nil);
end;
// Result is now a ctnUseUnit // Result is now a ctnUseUnit
Result:=Result.FirstChild; Result:=Result.FirstChild;
@ -10154,6 +10145,9 @@ var
Params.Flags:=[fdfSearchInAncestors,fdfExceptionOnNotFound,fdfSearchInHelpers] Params.Flags:=[fdfSearchInAncestors,fdfExceptionOnNotFound,fdfSearchInHelpers]
+(fdfGlobals*Params.Flags); +(fdfGlobals*Params.Flags);
Params.ContextNode:=Context.Node; Params.ContextNode:=Context.Node;
if Context.Node=nil then
RaiseException(20250101153139,'[TFindDeclarationTool.FindExpressionTypeOfTerm.ResolveIdentifier] internal error');
SearchForwardToo:=false; SearchForwardToo:=false;
if Context.Node=StartNode then begin if Context.Node=StartNode then begin
// there is no special context -> search in parent contexts too // there is no special context -> search in parent contexts too
@ -10166,26 +10160,23 @@ var
end else begin end else begin
// only search in special context // only search in special context
Params.Flags:=Params.Flags+[fdfIgnoreUsedUnits]; Params.Flags:=Params.Flags+[fdfIgnoreUsedUnits];
if Assigned(Context.Node) then begin if Context.Node.Desc=ctnImplementation then
if (Context.Node.Desc=ctnImplementation) then
Params.Flags:=Params.Flags+[fdfSearchInParentNodes]; Params.Flags:=Params.Flags+[fdfSearchInParentNodes];
if (Context.Node.Desc=ctnObjCClass) then if Context.Node.Desc=ctnObjCClass then
Exclude(Params.Flags,fdfExceptionOnNotFound); // ObjCClass has predefined identifiers like 'alloc' Exclude(Params.Flags,fdfExceptionOnNotFound); // ObjCClass has predefined identifiers like 'alloc'
end; end;
end;
// check identifier for overloaded procs // check identifier for overloaded procs
if Assigned(Context.Node) then begin
if (IsEnd and (fdfIgnoreOverloadedProcs in StartFlags)) if (IsEnd and (fdfIgnoreOverloadedProcs in StartFlags))
then then
Include(Params.Flags,fdfIgnoreOverloadedProcs); Include(Params.Flags,fdfIgnoreOverloadedProcs);
//debugln(['ResolveIdentifier ',IsEnd,' ',GetAtom(CurAtom),' ',Context.Node.DescAsString,' ',Context.Node.Parent.DescAsString,' ']); //debugln(['ResolveIdentifier ',IsEnd,' ',GetAtom(CurAtom),' ',Context.Node.DescAsString,' ',Context.Node.Parent.DescAsString,' ']);
if Assigned(Context.Node.Parent) and IsEnd and (Context.Node.Desc=ctnIdentifier) if IsEnd and Assigned(Context.Node.Parent) and (Context.Node.Desc=ctnIdentifier)
and (Context.Node.Parent.Desc=ctnAttribParam) and (Context.Node.Parent.Desc=ctnAttribParam)
and ResolveAttribute(Context) then begin and ResolveAttribute(Context) then
begin
exit; exit;
end; end;
end;
Params.SetIdentifier(Self,@Src[CurAtom.StartPos],@CheckSrcIdentifier Params.SetIdentifier(Self,@Src[CurAtom.StartPos],@CheckSrcIdentifier
{$IFDEF EnableFKnownIdentLength},FKnownIdentLength{$ENDIF}); {$IFDEF EnableFKnownIdentLength},FKnownIdentLength{$ENDIF});
@ -10239,9 +10230,15 @@ var
// first identifier is a used unit -> find longest fitting unitname // first identifier is a used unit -> find longest fitting unitname
//debugln(['ResolveIdentifier UseUnit FindLongest... ',Params.NewNode.DescAsString,' ',ExtractNode(Params.NewNode,[])]); //debugln(['ResolveIdentifier UseUnit FindLongest... ',Params.NewNode.DescAsString,' ',ExtractNode(Params.NewNode,[])]);
Params.NewNode:=ResolveUseUnit(Params.NewNode.Parent); Params.NewNode:=ResolveUseUnit(Params.NewNode.Parent);
// this might return nil!
//debugln(['ResolveIdentifier UseUnit FoundLongest: ',Params.NewNode.DescAsString,' ',ExtractNode(Params.NewNode,[])]); //debugln(['ResolveIdentifier UseUnit FoundLongest: ',Params.NewNode.DescAsString,' ',ExtractNode(Params.NewNode,[])]);
end; end;
ExprType.Context:=CreateFindContext(Params);
if Params.NewNode<>nil then
ExprType.Context:=CreateFindContext(Params)
else
ExprType.Desc:=xtNone;
Params.Load(OldInput,true); Params.Load(OldInput,true);
end else begin end else begin
// predefined identifier // predefined identifier

View File

@ -266,6 +266,7 @@ type
ScannedRange: TLinkScannerRange; // excluding the section with a syntax error ScannedRange: TLinkScannerRange; // excluding the section with a syntax error
ScanTill: TLinkScannerRange; ScanTill: TLinkScannerRange;
AddedNameSpace: string; // program, library and package namespace AddedNameSpace: string; // program, library and package namespace
HasNameSpaces: boolean; // the source name or a uses section uses namespaces
procedure ValidateToolDependencies; virtual; procedure ValidateToolDependencies; virtual;
procedure BuildTree(Range: TLinkScannerRange); procedure BuildTree(Range: TLinkScannerRange);
@ -796,6 +797,7 @@ begin
if CurPos.Flag=cafPoint then begin if CurPos.Flag=cafPoint then begin
if aNameSpace<>'' then aNameSpace:=aNameSpace+'.'; if aNameSpace<>'' then aNameSpace:=aNameSpace+'.';
aNameSpace:=aNameSpace+aName; aNameSpace:=aNameSpace+aName;
HasNameSpaces:=true;
end else end else
break; break;
until false; until false;
@ -2203,6 +2205,7 @@ begin
ReadNextAtom; ReadNextAtom;
if CurPos.Flag<>cafPoint then break; if CurPos.Flag<>cafPoint then break;
LastUnitNode.Desc:=ctnUseUnitNamespace; LastUnitNode.Desc:=ctnUseUnitNamespace;
HasNameSpaces:=true;
ReadNextAtom; ReadNextAtom;
AtomIsIdentifierSaveE(20180411194112); AtomIsIdentifierSaveE(20180411194112);
until false; until false;
@ -5699,6 +5702,8 @@ begin
if Tree.Root<>nil then if Tree.Root<>nil then
debugln(['TPascalParserTool.FetchScannerSource compiler clean all nodes, because compiler mode/values changed ',MainFilename]); debugln(['TPascalParserTool.FetchScannerSource compiler clean all nodes, because compiler mode/values changed ',MainFilename]);
{$ENDIF} {$ENDIF}
AddedNameSpace:='';
HasNameSpaces:=false;
end else begin end else begin
// find the first difference in source // find the first difference in source
OldP:=PChar(Src); OldP:=PChar(Src);

View File

@ -489,7 +489,7 @@ begin
while i>=0 do begin while i>=0 do begin
IdentItem:=CodeToolBoss.IdentifierList.FilteredItems[i]; IdentItem:=CodeToolBoss.IdentifierList.FilteredItems[i];
if IdentItem.Node<>nil then begin if IdentItem.Node<>nil then begin
FoundPath:=NodeAsPath(FoundTool,FoundNode); FoundPath:=NodeAsPath(IdentItem.Tool,IdentItem.Node);
//debugln(['TTestFindDeclaration.FindDeclarations i=',i,' FoundPath="',FoundPath,'"']); //debugln(['TTestFindDeclaration.FindDeclarations i=',i,' FoundPath="',FoundPath,'"']);
if SameText(ExpectedTerm,FoundPath) then if SameText(ExpectedTerm,FoundPath) then
break; break;