diff --git a/components/codetools/codetree.pas b/components/codetools/codetree.pas index 0e110ecf11..2b2298fb6a 100644 --- a/components/codetools/codetree.pas +++ b/components/codetools/codetree.pas @@ -58,7 +58,7 @@ const // CodeTreeNodeDescriptors ctnNone = 0; - ctnProgram = 1; + ctnProgram = 1; // children are ctnInterface, each namespace and sourcename ctnPackage = 2; ctnLibrary = 3; ctnUnit = 4; diff --git a/components/codetools/finddeclarationtool.pas b/components/codetools/finddeclarationtool.pas index b84ab38cf9..e2d57fa60e 100644 --- a/components/codetools/finddeclarationtool.pas +++ b/components/codetools/finddeclarationtool.pas @@ -8951,8 +8951,10 @@ var function ResolveUseUnit(StartUseUnitNode: TCodeTreeNode): TCodeTreeNode; // IsStart=true, NextAtomType=vatPoint, // StartUseUnitNameNode.Desc=ctnUseUnit - // -> Find the longest namespaced used unit, that fits the start of the + // -> Find the longest namespaced used unit (ctnUseUnitNamespace,ctnUseUnitClearName) + // or the source name (ctnIdentifier), that fits the start of the // current identifier a.b.c... + // function GetPrevUseUnit(UseUnitNode: TCodeTreeNode): TCodeTreeNode; begin @@ -9012,7 +9014,7 @@ var until CurPos.Flag<>cafPoint; //debugln(['ResolveUsenit DottedIdentifier="',DottedIdentifier,'"']); - // find longest dotted unit name in uses + // find longest dotted unit name in uses and source name UseUnitNode:=StartUseUnitNode; BestNode:=nil; BestLevel:=0; @@ -9022,13 +9024,13 @@ var if (Node<>nil) and CompareSrcIdentifiers(CurAtom.StartPos,Node.StartPos) then begin // found candidate - //debugln(['ResolveUsenit Candidate=',ExtractNode(Node,[])]); + //debugln(['ResolveUseUnit Candidate=',ExtractNode(Node,[])]); Level:=1; p:=PChar(DottedIdentifier); repeat inc(p,GetIdentLen(p)); if p^='.' then inc(p); - //writeln('ResolveUsenit p=',p,' NextBrother=',Node.NextBrother<>nil); + //writeln('ResolveUseUnit p=',p,' NextBrother=',Node.NextBrother<>nil); if Node.NextBrother=nil then begin // fits if Level>BestLevel then begin @@ -9041,7 +9043,7 @@ var break; end else begin Node:=Node.NextBrother; - //writeln('ResolveUsenit p=',p,' node=',GetIdentifier(@Src[Node.StartPos])); + //writeln('ResolveUseUnit p=',p,' node=',GetIdentifier(@Src[Node.StartPos])); if not CompareSrcIdentifiers(Node.StartPos,p) then break; inc(Level); @@ -9049,10 +9051,61 @@ var until false; end; until UseUnitNode=nil; - //debugln(['ResolveUsenit collected candidates Best=',ExtractNode(BestNode,[])]); + //debugln(['ResolveUseUnit collected candidates Best=',ExtractNode(BestNode,[])]); - Result:=BestNode.FirstChild; + //debugln(['ResolveUseUnit Src=',Tree.Root.DescAsString,' Name=',GetSourceName(false),' DottedIdentifier="',DottedIdentifier,'"']); + // check source name + if (Tree.Root.Desc in AllSourceTypes) + and (Tree.Root.FirstChild<>nil) + and CompareSrcIdentifiers(Tree.Root.FirstChild.StartPos,PChar(DottedIdentifier)) + then begin + // found candidate + Level:=1; + Node:=Tree.Root.FirstChild; + //debugln(['ResolveUseUnit Candidate SrcName']); + p:=PChar(DottedIdentifier); + repeat + //debugln('ResolveUseUnit SrcName p=',p,' Node=',ExtractNode(Node,[])); + if (Node.NextBrother=nil) or (Node.NextBrother.Desc<>ctnIdentifier) then begin + // fits + //debugln(['ResolveUseUnit FITS Level=',Level,' Best=',BestLevel]); + if Level>BestLevel then begin + // source name fits best + Result:=Tree.Root.FirstChild; + // move cursor forward + while (Result.NextBrother<>nil) + and (NextAtom.EndPosctnIdentifier) then + exit(Tree.Root); + ReadNextExpressionAtom; // read point + ReadNextExpressionAtom; // read namespace/unitname + //debugln(['ResolveUseUnit Next ',GetAtom(CurAtom)]); + Result:=Result.NextBrother; + end; + exit; + //debugln(['ResolveUseUnit SrcName fits better']); + end; + break; + end else if p^=#0 then begin + // source name too long + break; + end else begin + Node:=Node.NextBrother; + inc(p,GetIdentLen(p)); + if p^='.' then inc(p); + //debugln('ResolveUseUnit SrcName NEXT p=',p,' Node=',ExtractNode(Node,[])); + if not CompareSrcIdentifiers(Node.StartPos,p) then + break; + inc(Level); + end; + until false; + end; + Result:=BestNode; + if Result=nil then exit; + + // Result is now a ctnUseUnit + Result:=Result.FirstChild; // move cursor forward while (Result.NextBrother<>nil) and (NextAtom.EndPoslsttWord) - or WordIsKeyWord.DoItCaseInsensitive(@Src[SrcPos]) then exit(false); - ReadNextToken; + repeat + ReadNextToken; + if (TokenType<>lsttWord) + or WordIsKeyWord.DoItCaseInsensitive(@Src[SrcPos]) then exit(false); + ReadNextToken; + until TokenType<>lsttPoint; if TokenIs('in') then begin // read "in" filename ReadNextToken; diff --git a/components/codetools/pascalparsertool.pas b/components/codetools/pascalparsertool.pas index f0328e4c37..449e9e459d 100644 --- a/components/codetools/pascalparsertool.pas +++ b/components/codetools/pascalparsertool.pas @@ -690,6 +690,10 @@ begin if (CurPos.Flag<>cafWord) or (CurSection in [ctnUnit,ctnPackage]) then AtomIsIdentifierSaveE; + CreateChildNode; + CurNode.Desc:=ctnIdentifier; + CurNode.EndPos:=CurPos.EndPos; + EndChildNode; aName:=GetAtom; ReadNextAtom; // read ';' (or 'platform;' or 'unimplemented;') if CurPos.Flag=cafPoint then begin @@ -2093,8 +2097,10 @@ begin EndChildNode; if CurPos.Flag=cafSemicolon then break; if CurPos.Flag<>cafComma then - if ExceptionOnError then - SaveRaiseCharExpectedButAtomFound(20170421195538,';') + if ExceptionOnError then begin + CTDumpStack; + SaveRaiseCharExpectedButAtomFound(20170421195538,';'); + end else exit; until (CurPos.StartPos>SrcLen); CurNode.EndPos:=CurPos.EndPos; diff --git a/components/codetools/tests/laztests/unitdots.dot.pas b/components/codetools/tests/laztests/unitdots.dot.pas index faa41e0c5c..f6a3d8884f 100644 --- a/components/codetools/tests/laztests/unitdots.dot.pas +++ b/components/codetools/tests/laztests/unitdots.dot.pas @@ -4,6 +4,8 @@ unit unitdots.dot; interface +type + TColor = longint; var test: integer; foo: integer;