diff --git a/components/codetools/basiccodetools.pas b/components/codetools/basiccodetools.pas index d8a6d9bfdd..c21c529d62 100644 --- a/components/codetools/basiccodetools.pas +++ b/components/codetools/basiccodetools.pas @@ -94,7 +94,7 @@ function FindLineEndOrCodeInFrontOfPosition(const Source: string; StopAtDirectives: boolean = true): integer; function FindLineEndOrCodeAfterPosition(const Source: string; Position, MaxPosition: integer; NestedComments: boolean; - StopAtDirectives: boolean = true): integer; + StopAtDirectives: boolean = true; SkipEmptyLines: boolean = false): integer; function FindFirstLineEndInFrontOfInCode(const Source: string; Position, MinPosition: integer; NestedComments: boolean): integer; function FindFirstLineEndAfterInCode(const Source: string; @@ -1752,10 +1752,32 @@ end; function FindLineEndOrCodeAfterPosition(const Source: string; Position, MaxPosition: integer; NestedComments: boolean; - StopAtDirectives: boolean): integer; + StopAtDirectives: boolean; SkipEmptyLines: boolean): integer; { search forward for a line end or code ignore line ends in comments Result is Position of Start of Line End + + if SkipEmptyLines=true, it will skip empty lines at the end + + Examples: | is the Position and # is the Result + + 1. var i: integer;|# + var j: integer; + + 2. var i: integer;| (* + *) #var j: integer; + + 3. SkipEmptyLines=false + var i: integer;| + # + // comment + var j: integer; + + 4. SkipEmptyLines=true + var i: integer;| + + #// comment + var j: integer; } var SrcLen: integer; @@ -1809,6 +1831,27 @@ var SrcLen: integer; end; Result:=true; end; + + procedure DoSkipEmptyLines(var p: integer); + var + OldPos: LongInt; + begin + OldPos:=p; + repeat + while (p<=SrcLen) and (Source[p] in [' ',#9]) do inc(p); + if (p<=SrcLen) and (Source[p] in [#10,#13]) then begin + // an empty line => skip + OldPos:=p;// remember position in front of new line characters + inc(p); + if (p<=SrcLen) and (Source[p] in [#10,#13]) and (Source[p]<>Source[p-1]) + then + inc(p); + end else begin + p:=OldPos; + exit; + end; + until false; + end; begin SrcLen:=length(Source); @@ -1820,7 +1863,10 @@ begin '{','(','/': if not ReadComment(Result) then exit; #10,#13: - exit; + begin + if SkipEmptyLines then DoSkipEmptyLines(Result); + exit; + end; #9,' ',';': inc(Result); else diff --git a/components/codetools/codecompletiontool.pas b/components/codetools/codecompletiontool.pas index 3caef2ad80..249b584305 100644 --- a/components/codetools/codecompletiontool.pas +++ b/components/codetools/codecompletiontool.pas @@ -1363,54 +1363,82 @@ var procedure CheckAlias(Node: TCodeTreeNode); var - WrongType: Boolean; ReferingNode: TCodeTreeNode; ReferingNodeText: String; ReferingPos: LongInt; NodeExt: TCodeTreeNodeExtension; AVLNode: TAVLTreeNode; - begin - // check if definition is an alias - // Example: const A = B; - if (Node.Parent=nil) then exit; - if not (Node.Parent.Desc in [ctnConstSection,ctnTypeSection]) then exit; - // this is a const or type - MoveCursorToNodeStart(Node); - ReadNextAtom; - if CurPos.Flag<>cafWord then exit; - ReadNextAtom; - if CurPos.Flag<>cafEqual then exit; - ReadNextAtom; - if CurPos.Flag<>cafWord then exit; - ReferingPos:=CurPos.StartPos; - ReadNextAtom; - if CurPos.Flag<>cafSemicolon then exit; - - // this is a const or type alias - //DebugLn(['TCodeCompletionCodeTool.FindAliasDefinitions Alias: ',Node.DescAsString,' ',ExtractNode(Node,[])]); - WrongType:=false; - ReferingNode:=nil; - if OnlyWrongType then begin + BracketStartPos: LongInt; + NeededType: TCodeTreeNodeDesc; + + procedure GetReferingNode; + begin + if ReferingNodeText<>'' then exit; ReferingNodeText:=GetIdentifier(@Src[ReferingPos]); AVLNode:=FindCodeTreeNodeExtAVLNode(AllNodes,ReferingNodeText); if (AVLNode<>nil) then begin NodeExt:=TCodeTreeNodeExtension(AVLNode.Data); ReferingNode:=NodeExt.Node; - if ReferingNode.Desc<>Node.Desc then begin - // this alias has wrong type - WrongType:=true; - DebugLn(['TCodeCompletionCodeTool.FindAliasDefinitions Wrong: ',Node.DescAsString,' ',ExtractNode(Node,[]),' ',Node.DescAsString,'<>',ReferingNode.DescAsString]); + end; + end; + + begin + // check if definition is an alias + // Example: const A = B; or const A = B(); + if (Node.Parent=nil) then exit; + if not (Node.Parent.Desc in [ctnConstSection,ctnTypeSection]) then exit; + // this is a const or type + MoveCursorToNodeStart(Node); + // read A + ReadNextAtom; + if CurPos.Flag<>cafWord then exit; + // read = + ReadNextAtom; + if CurPos.Flag<>cafEqual then exit; + // read B + ReadNextAtom; + if CurPos.Flag<>cafWord then exit; + ReferingPos:=CurPos.StartPos; + ReadNextAtom; + if CurPos.Flag=cafRoundBracketOpen then begin + BracketStartPos:=CurPos.StartPos; + ReadTilBracketClose(true); + //BracketEndPos:=CurPos.StartPos; + ReadNextAtom; + end else + BracketStartPos:=0; + if CurPos.Flag<>cafSemicolon then exit; + + ReferingNode:=nil; + NeededType:=ctnNone; + + if BracketStartPos>0 then begin + if WordIsKeyWord.DoIt(@Src[ReferingPos]) then exit; + // this is a type cast + NeededType:=ctnConstDefinition; + end else begin + // this is a const or type alias + //DebugLn(['TCodeCompletionCodeTool.FindAliasDefinitions Alias: ',Node.DescAsString,' ',ExtractNode(Node,[])]); + if OnlyWrongType then begin + GetReferingNode; + if (ReferingNode<>nil) then begin + NeededType:=ReferingNode.Desc; end; end; end; - if WrongType or (not OnlyWrongType) then begin + if NeededType=ctnNone then exit; + if (NeededType<>Node.Desc) or (not OnlyWrongType) then begin // add alias + if NeededType<>Node.Desc then begin + DebugLn(['TCodeCompletionCodeTool.FindAliasDefinitions Wrong: ',Node.DescAsString,' ',ExtractNode(Node,[]),' ',Node.DescAsString,'<>',ReferingNode.DescAsString]); + end; if TreeOfCodeTreeNodeExt=nil then TreeOfCodeTreeNodeExt:=TAVLTree.Create(@CompareCodeTreeNodeExt); NodeExt:=NodeExtMemManager.NewNode; NodeExt.Node:=Node; NodeExt.Txt:=GetRedefinitionNodeText(Node); NodeExt.Data:=ReferingNode; + NodeExt.Flags:=NeededType; TreeOfCodeTreeNodeExt.Add(NodeExt); end; end; @@ -1492,7 +1520,7 @@ function TCodeCompletionCodeTool.FixAliasDefinitions( ): boolean; { replaces public dummy functions with a constant. The function body will be removed. - See the function FindConstFunctions. + See the function FindAliasDefinitions. } function FindReferingNode(DefNode: TCodeTreeNode): TCodeTreeNode; var @@ -1521,6 +1549,7 @@ var ReferingNodeBehind: TCodeTreeNode; NewSrc: String; FromPos: LongInt; + ReferingType: TCodeTreeNodeDesc; begin Result:=false; if SourceChangeCache=nil then exit; @@ -1535,9 +1564,10 @@ begin NodeExt:=TCodeTreeNodeExtension(AVLNode.Data); DefNode:=NodeExt.Node; ReferingNode:=TCodeTreeNode(NodeExt.Data); + ReferingType:=TCodeTreeNodeDesc(NodeExt.Flags); if (ReferingNode=nil) or (not (ReferingNode.Desc in [ctnTypeDefinition,ctnConstDefinition])) - or (DefNode.Desc=ReferingNode.Desc) then begin + or (DefNode.Desc=ReferingType) then begin TreeOfCodeTreeNodeExt.Delete(AVLNode); end; AVLNode:=NextAVLNode; @@ -1549,10 +1579,11 @@ begin NodeExt:=TCodeTreeNodeExtension(AVLNode.Data); DefNode:=NodeExt.Node; ReferingNode:=TCodeTreeNode(NodeExt.Data); + ReferingType:=TCodeTreeNodeDesc(NodeExt.Flags); - //DebugLn(['TCodeCompletionCodeTool.FixAliasDefinitions Old=',DefNode.DescAsString,' New=',ReferingNode.DescAsString]); + //DebugLn(['TCodeCompletionCodeTool.FixAliasDefinitions Old=',DefNode.DescAsString,' New=',NodeDescToStr(ReferingType)]); - case ReferingNode.Desc of + case ReferingType of ctnTypeDefinition: NewSrc:='type'; ctnConstDefinition: NewSrc:='const'; else NewSrc:='bug'; @@ -1569,7 +1600,7 @@ begin // this is not the start of the section ReferingNodeInFront:=FindReferingNode(DefNode.PriorBrother); if (ReferingNodeInFront=nil) - or (ReferingNodeInFront.Desc<>ReferingNode.Desc) then begin + or (ReferingNodeInFront.Desc<>ReferingType) then begin // the node in front has a different section FromPos:=FindLineEndOrCodeInFrontOfPosition(DefNode.StartPos); if not SourceChangeCache.Replace(gtEmptyLine,gtNewLine, @@ -1592,9 +1623,11 @@ begin ctnConstDefinition: NewSrc:='const'; else NewSrc:=''; end; - FromPos:=FindLineEndOrCodeInFrontOfPosition(DefNode.NextBrother.StartPos); - if not SourceChangeCache.Replace(gtEmptyLine,gtNewLine, - FromPos,FromPos,NewSrc) then exit; + if NewSrc<>'' then begin + FromPos:=FindLineEndOrCodeInFrontOfPosition(DefNode.NextBrother.StartPos); + if not SourceChangeCache.Replace(gtEmptyLine,gtNewLine, + FromPos,FromPos,NewSrc) then exit; + end; end; end; @@ -1892,7 +1925,7 @@ var ResultType: PChar; begin if (ProcNode=nil) or (ProcNode.Desc<>ctnProcedure) then exit; - DebugLn(['CheckProcNode START ',ExtractProcHead(ProcNode,[])]); + //DebugLn(['CheckProcNode START ',ExtractProcHead(ProcNode,[])]); MoveCursorToNodeStart(ProcNode); ReadNextAtom; // read 'function' @@ -1954,7 +1987,7 @@ var end; if Node.Desc<>ctnBeginBlock then exit; - DebugLn(['CheckProcNode has begin block']); + //DebugLn(['CheckProcNode has begin block']); // check begin block is only a single assignment MoveCursorToNodeStart(Node); @@ -1982,7 +2015,7 @@ var // read ) ReadNextAtom; if CurPos.Flag<>cafRoundBracketClose then exit; - DebugLn(['CheckProcNode FOUND']); + //DebugLn(['CheckProcNode FOUND']); // save values ResultNodeExt:=NodeExtMemManager.NewNode; @@ -2428,7 +2461,7 @@ function TCodeCompletionCodeTool.FixForwardDefinitions( if Node.Desc=ctnTypeSection then begin // remove type section FromPos:=FindLineEndOrCodeInFrontOfPosition(Node.StartPos); - ToPos:=FindLineEndOrCodeAfterPosition(Node.EndPos); + ToPos:=FindLineEndOrCodeAfterPosition(Node.EndPos,true); DebugLn(['CreateTypeSectionForCircle Removing type section: ',ExtractCode(FromPos,ToPos,[])]); SourceChangeCache.Replace(gtNone,gtNone,FromPos,ToPos,''); // add all types of type section to new type section @@ -2457,7 +2490,6 @@ function TCodeCompletionCodeTool.FixForwardDefinitions( if not Result then exit; // rebuild graph Result:=UpdateGraph(Definitions,Graph,true); - DebugLn(['CreateTypeSectionForCircle ',Src]); end; function FixCircle(var Definitions: TAVLTree; @@ -2553,7 +2585,7 @@ function TCodeCompletionCodeTool.FixForwardDefinitions( try Graph.DeleteSelfCircles; repeat - WriteCodeGraphDebugReport(Graph); + //WriteCodeGraphDebugReport(Graph); CircleEdge:=Graph.GetTopologicalSortedList(ListOfGraphNodes,true,false,false); if CircleEdge=nil then break; DebugLn(['FixForwardDefinitions.CheckCircles Circle found containing ', @@ -2613,7 +2645,18 @@ function TCodeCompletionCodeTool.FixForwardDefinitions( Node:=GetFirstVarDefSequenceNode(Node); while (Node<>nil) do begin if not NodeWillBeMoved(Node) then exit(false); - if (Node.FirstChild<>nil) then break; + if (Node.FirstChild<>nil) then break;// this is the last of the sequence + Node:=Node.NextBrother; + end; + Result:=true; + end; + + function WholeSectionWillBeMoved(Node: TCodeTreeNode): boolean; + // test, if all child nodes will be moved + begin + Node:=Node.FirstChild; + while (Node<>nil) do begin + if not NodeWillBeMoved(Node) then exit(false); Node:=Node.NextBrother; end; Result:=true; @@ -2622,16 +2665,16 @@ function TCodeCompletionCodeTool.FixForwardDefinitions( var AVLNode: TAVLTreeNode; CurMove: TNodeMoveEdge; - GraphNode: TCodeGraphNode; - PosGraphNode: TCodeGraphNode; + GraphNode: TCodeGraphNode;// move what + PosGraphNode: TCodeGraphNode;// move where (in front of) Node: TCodeTreeNode; FromPos: LongInt; ToPos: LongInt; DestNode: TCodeTreeNode; NextAVLNode: TAVLTreeNode; NextMove: TNodeMoveEdge; - NextGraphNode: TCodeGraphNode; - NextPosGraphNode: TCodeGraphNode; + NextGraphNode: TCodeGraphNode;// move what next + NextPosGraphNode: TCodeGraphNode;// move where next (in front of) NextInsertAtSamePos: boolean; NeedSection: TCodeTreeNodeDesc; LastSection: TCodeTreeNodeDesc; @@ -2640,6 +2683,7 @@ function TCodeCompletionCodeTool.FixForwardDefinitions( Indent: LongInt; DestSection: TCodeTreeNodeDesc; NewTxt: String; + DestNodeInFront: TCodeTreeNode; begin Result:=false; AVLNode:=TreeOfNodeMoveEdges.FindLowest; @@ -2647,15 +2691,16 @@ function TCodeCompletionCodeTool.FixForwardDefinitions( LastInsertAtSamePos:=false; DestNode:=nil; DestSection:=ctnNone; + // process every move while AVLNode<>nil do begin CurMove:=TNodeMoveEdge(AVLNode.Data); - GraphNode:=CurMove.GraphNode; - PosGraphNode:=TCodeGraphNode(GraphNode.Data); + GraphNode:=CurMove.GraphNode;// move what + PosGraphNode:=TCodeGraphNode(GraphNode.Data);// move where (in front of) NextAVLNode:=TreeOfNodeMoveEdges.FindSuccessor(AVLNode); if NextAVLNode<>nil then begin NextMove:=TNodeMoveEdge(NextAVLNode.Data); - NextGraphNode:=NextMove.GraphNode; - NextPosGraphNode:=TCodeGraphNode(NextGraphNode.Data); + NextGraphNode:=NextMove.GraphNode;// move what next + NextPosGraphNode:=TCodeGraphNode(NextGraphNode.Data);// move where next NextInsertAtSamePos:=NextPosGraphNode=PosGraphNode; end else begin NextInsertAtSamePos:=false; @@ -2669,7 +2714,23 @@ function TCodeCompletionCodeTool.FixForwardDefinitions( DestNode:=PosGraphNode.Node; // remove node - if Node.Desc=ctnVarDefinition then begin + if (Node.Parent<>nil) + and (Node.Parent.Desc in AllDefinitionSections) + and WholeSectionWillBeMoved(Node.Parent) then begin + // the whole type/var/const section will be moved + if Node.PriorBrother=nil then begin + // this is the first node of the section + // => remove the whole section + FromPos:=FindLineEndOrCodeInFrontOfPosition(Node.Parent.StartPos); + ToPos:=FindLineEndOrCodeAfterPosition(Node.Parent.EndPos,true); + end else begin + // this is not the first node of the section + // => remove nothing + FromPos:=0; + ToPos:=0; + end; + end + else if Node.Desc=ctnVarDefinition then begin // removing a variable definition can be tricky, because for example // var a,b,c: integer; if Node.FirstChild<>nil then begin @@ -2681,7 +2742,7 @@ function TCodeCompletionCodeTool.FixForwardDefinitions( FromPos:=FindLineEndOrCodeInFrontOfPosition( GetFirstVarDefSequenceNode(Node).StartPos); ToPos:=FindLineEndOrCodeAfterPosition( - GetLastVarDefSequenceNode(Node).EndPos); + GetLastVarDefSequenceNode(Node).EndPos,true); end else if NodeWillBeMoved(Node.PriorBrother) then begin // this is for example: var a,b,c: integer // and only b and c will be moved. The b, plus the space behind was @@ -2691,8 +2752,7 @@ function TCodeCompletionCodeTool.FixForwardDefinitions( MoveCursorToNodeStart(Node); ReadNextAtom;// read identifier AtomIsIdentifier(true); - ReadNextAtom;// read colon - ToPos:=CurPos.StartPos; + ToPos:=FindLineEndOrCodeAfterPosition(CurPos.EndPos,true); end else begin // this is for example: var a,b: integer // and only b will be moved. @@ -2717,8 +2777,8 @@ function TCodeCompletionCodeTool.FixForwardDefinitions( FromPos:=0; ToPos:=0; end else begin - // remove the name plus the next comma - FromPos:=Node.StartPos; + // remove the b, + FromPos:=FindLineEndOrCodeInFrontOfPosition(Node.StartPos); MoveCursorToNodeStart(Node); ReadNextAtom;// read identifier AtomIsIdentifier(true); @@ -2738,44 +2798,65 @@ function TCodeCompletionCodeTool.FixForwardDefinitions( exit; end; + // find needed section type + if Node.Desc in AllIdentifierDefinitions then + NeedSection:=Node.Parent.Desc + else + NeedSection:=ctnNone; + // find insert position if not LastInsertAtSamePos then begin + //DebugLn(['MoveNodes LastInsertAtSamePos=false, compute destination ...']); if (DestNode.Desc in AllIdentifierDefinitions) then begin DestNode:=GetFirstVarDefSequenceNode(DestNode); + DestSection:=DestNode.Parent.Desc; if DestNode.PriorBrother<>nil then begin // the destination is in front of a definition, but in the middle // of a section // example: type a=char; | b=byte; // => insert in front of destination - DestSection:=DestNode.Parent.Desc; + //DebugLn(['MoveNodes destination is middle of a section. Node in front=',GetRedefinitionNodeText(DestNode.PriorBrother)]); end else begin // the destination is the first node of a section // example: type | t=char; - // => insert in front of the section - DestNode:=DestNode.Parent; - DestSection:=DestNode.Desc; + if NeedSection=DestSection then begin + // insertion needs the same section type + // => insert in front of destination + end else begin + // insertion needs another section type + // => insert in front of the section + DestNode:=DestNode.Parent; + end; + //DebugLn(['MoveNodes destination is first node of a section ']); end; end else begin // the destination is not in a section // example: in front of a type section // => insert in front of destination - DestSection:=DestNode.Desc; + // find the section in front + DestNodeInFront:=DestNode.PriorBrother; + while (DestNodeInFront<>nil) and NodeWillBeMoved(DestNodeInFront) do + DestNodeInFront:=DestNodeInFront.PriorBrother; + if (DestNodeInFront<>nil) + and (DestNodeInFront.Desc in AllDefinitionSections) then + DestSection:=DestNodeInFront.Desc + else + DestSection:=ctnNone; + //DebugLn(['MoveNodes destination is not in a section']); end; InsertPos:=FindLineEndOrCodeAfterPosition(DestNode.StartPos); Indent:=GetLineIndent(Src,DestNode.StartPos); + //DebugLn(['MoveNodes DestNode=',GetRedefinitionNodeText(DestNode),':',DestNode.DescAsString,' DestSection=',NodeDescToStr(DestSection)]); end; // start a new section if needed - if Node.Desc in AllIdentifierDefinitions then - NeedSection:=Node.Parent.Desc - else - NeedSection:=ctnNone; + //DebugLn(['MoveNodes LastInsertAtSamePos=',LastInsertAtSamePos,' NeedSection=',NodeDescToStr(NeedSection),' LastSection=',NodeDescToStr(LastSection),' DestSection=',NodeDescToStr(DestSection)]); if (LastInsertAtSamePos and (NeedSection<>LastSection)) - or ((not LastInsertAtSamePos) and (NeedSection<>DestNode.Desc)) then begin + or ((not LastInsertAtSamePos) and (NeedSection<>DestSection)) then begin // start a new section case NeedSection of - ctnVarDefinition: NewTxt:='var'; - ctnConstDefinition: NewTxt:='const'; + ctnVarSection: NewTxt:='var'; + ctnConstSection: NewTxt:='const'; ctnResStrSection: NewTxt:='resourcestring'; ctnTypeSection: NewTxt:='type'; ctnLabelSection: NewTxt:='label'; @@ -2787,6 +2868,7 @@ function TCodeCompletionCodeTool.FixForwardDefinitions( InsertPos,InsertPos,NewTxt) then exit; + Indent:=SourceChangeCache.BeautifyCodeOptions.Indent; end; end; @@ -2807,8 +2889,6 @@ function TCodeCompletionCodeTool.FixForwardDefinitions( NewTxt:=ExtractCode(FromPos,ToPos,[phpWithComments]); end; NewTxt:=GetIndentStr(Indent)+NewTxt; - if Node.Desc in AllIdentifierDefinitions then - NewTxt:=GetIndentStr(SourceChangeCache.BeautifyCodeOptions.Indent)+NewTxt; DebugLn(['MoveNodes insert "',NewTxt,'"']); if not SourceChangeCache.Replace(gtNewLine,gtNewLine,InsertPos,InsertPos, NewTxt) then exit; @@ -2864,7 +2944,8 @@ function TCodeCompletionCodeTool.FixForwardDefinitions( ListOfGraphNodes:=nil; NodeMoveEdges:=TAVLTree.Create(@CompareNodeMoveEdges); try - WriteCodeGraphDebugReport(Graph); + //WriteCodeGraphDebugReport(Graph); + // create a topologically sorted list CircleEdge:=Graph.GetTopologicalSortedList(ListOfGraphNodes,false,true,false); if CircleEdge<>nil then @@ -2888,7 +2969,7 @@ function TCodeCompletionCodeTool.FixForwardDefinitions( // init the destinations for i:=0 to ListOfGraphNodes.Count-1 do begin GraphNode:=TCodeGraphNode(ListOfGraphNodes[i]); - DebugLn(['CheckOrder ',GetRedefinitionNodeText(GraphNode.Node)]); + //DebugLn(['CheckOrder ',GetRedefinitionNodeText(GraphNode.Node)]); GraphNode.Data:=GraphNode; end; // calculate the destinations as minimum of all dependencies @@ -2901,7 +2982,7 @@ function TCodeCompletionCodeTool.FixForwardDefinitions( // for example: type TMyPointer = TMyInteger; // GraphNode.Node is TMyInteger // UsedByGraphNode.Node is TMyPointer - DebugLn(['CheckOrder GraphNode=',GetRedefinitionNodeText(GraphNode.Node),' UsedBy=',GetRedefinitionNodeText(UsedByGraphNode.Node)]); + //DebugLn(['CheckOrder GraphNode=',GetRedefinitionNodeText(GraphNode.Node),' UsedBy=',GetRedefinitionNodeText(UsedByGraphNode.Node)]); PosGraphNode:=TCodeGraphNode(GraphNode.Data); PosUsedByGraphNode:=TCodeGraphNode(UsedByGraphNode.Data); if PosGraphNode.Node.StartPos>PosUsedByGraphNode.Node.StartPos then @@ -2951,8 +3032,8 @@ begin try // Workaround: // move the pointer types to the same type sections - if not MovePointerTypesToTargetSections(SourceChangeCache) then exit; - exit(true); + //if not MovePointerTypesToTargetSections(SourceChangeCache) then exit; + //exit(true); if not BuildUnitDefinitionGraph(Definitions,Graph,true) or (Graph=nil) then exit; diff --git a/components/codetools/customcodetool.pas b/components/codetools/customcodetool.pas index 4e16192fc6..2209cca992 100644 --- a/components/codetools/customcodetool.pas +++ b/components/codetools/customcodetool.pas @@ -200,7 +200,8 @@ type ResolveComments: boolean; var SameArea: TAtomPosition); procedure GetLineInfo(ACleanPos: integer; var ALineStart, ALineEnd, AFirstAtomStart, ALastAtomEnd: integer); - function FindLineEndOrCodeAfterPosition(StartPos: integer): integer; + function FindLineEndOrCodeAfterPosition(StartPos: integer; + SkipEmptyLines: boolean = false): integer; function FindLineEndOrCodeInFrontOfPosition(StartPos: integer): integer; function FindLineEndOrCodeInFrontOfPosition(StartPos: integer; StopAtDirectives: boolean): integer; @@ -2240,8 +2241,8 @@ begin end; end; -function TCustomCodeTool.FindLineEndOrCodeAfterPosition(StartPos: integer - ): integer; +function TCustomCodeTool.FindLineEndOrCodeAfterPosition(StartPos: integer; + SkipEmptyLines: boolean): integer; { Searches a nice position in the cleaned source after StartPos. It will skip any space or comments (not directives) till next line end or compiler directive or code or include file end. @@ -2253,7 +2254,7 @@ begin LinkEnd:=Scanner.LinkCleanedEndPos(LinkIndex); if LinkEnd>StartPos then Result:=BasicCodeTools.FindLineEndOrCodeAfterPosition(Src, - StartPos,LinkEnd-1,Scanner.NestedComments) + StartPos,LinkEnd-1,Scanner.NestedComments,true,SkipEmptyLines) else Result:=StartPos; end; diff --git a/components/codetools/examples/fixdefinitionorder.lpi b/components/codetools/examples/fixdefinitionorder.lpi index 9934345049..b0130c5c56 100644 --- a/components/codetools/examples/fixdefinitionorder.lpi +++ b/components/codetools/examples/fixdefinitionorder.lpi @@ -26,28 +26,18 @@ - + - + - + - - - - - - - - - - diff --git a/components/h2pas/h2pasconvert.pas b/components/h2pas/h2pasconvert.pas index 3b7d094d32..815e7c3d93 100644 --- a/components/h2pas/h2pasconvert.pas +++ b/components/h2pas/h2pasconvert.pas @@ -102,8 +102,18 @@ type end; + { TRemoveDoubleSemicolons - + Remove double semicolons } + + TRemoveDoubleSemicolons = class(TCustomTextConverterTool) + public + class function ClassDescription: string; override; + function Execute(aText: TIDETextConverter): TModalResult; override; + end; + + { TRemoveSystemTypes - - Remove type redefinitons like PLongint } + Remove type redefinitions like PLongint } TRemoveSystemTypes = class(TCustomTextConverterTool) public @@ -290,6 +300,7 @@ type TPostH2PasToolsOption = ( phReplaceUnitFilenameWithUnitName, // Replace "unit filename;" with "unit name;" phRemoveIncludeDirectives, // remove include directives + phRemoveDoubleSemicolons, // Remove double semicolons phRemoveSystemTypes, // Remove type redefinitons like PLongint phFixH2PasMissingIFDEFsInUnit, // add missing IFDEFs for function bodies phReduceCompilerDirectivesInUnit, // removes unneeded directives @@ -2301,7 +2312,7 @@ end; class function TRemoveSystemTypes.ClassDescription: string; begin - Result:='Remove type redefinitons like PLongint'; + Result:='Remove type redefinitions like PLongint'; end; function TRemoveSystemTypes.Execute(aText: TIDETextConverter): TModalResult; @@ -2314,6 +2325,7 @@ begin Result:=mrCancel; if aText=nil then exit; Source:=aText.Source; + Flags:=[sesoReplace,sesoReplaceAll,sesoRegExpr]; Prompt:=false; SearchFor:='^\s*(' @@ -2327,6 +2339,12 @@ begin +');\s*$'; Result:=IDESearchInText('',Source,SearchFor,'',Flags,Prompt,nil); if Result<>mrOk then exit; + + // replace NULL with nil + Flags:=[sesoReplace,sesoReplaceAll,sesoRegExpr,sesoMatchCase]; + Result:=IDESearchInText('',Source,'\bNULL\b','nil',Flags,Prompt,nil); + if Result<>mrOk then exit; + aText.Source:=Source; end; @@ -3644,6 +3662,8 @@ begin TReplaceUnitFilenameWithUnitName,Result) then exit; if not Run(phRemoveIncludeDirectives, TRemoveIncludeDirectives,Result) then exit; + if not Run(phRemoveDoubleSemicolons, + TRemoveDoubleSemicolons,Result) then exit; if not Run(phRemoveSystemTypes, TRemoveSystemTypes,Result) then exit; if not Run(phFixH2PasMissingIFDEFsInUnit, @@ -3843,4 +3863,70 @@ begin Result:=mrOk; end; +{ TRemoveDoubleSemicolons } + +class function TRemoveDoubleSemicolons.ClassDescription: string; +begin + Result:='Remove double semicolons'; +end; + +function TRemoveDoubleSemicolons.Execute(aText: TIDETextConverter + ): TModalResult; +var + Position: Integer; + Source, NewSrc: String; + AtomStart: integer; + LastAtomWasSemicolon: Boolean; + SemicolonPositions: array of integer; + SemicolonCount: Integer; + i: Integer; +begin + Result:=mrCancel; + if aText=nil then exit; + Source:=aText.Source; + + // find all double semicolons + Position:=1; + LastAtomWasSemicolon:=false; + Setlength(SemicolonPositions,0); + SemicolonCount:=0; + repeat + ReadRawNextPascalAtom(Source,Position,AtomStart,true); + if AtomStart>length(Source) then break; + if Source[AtomStart]=';' then begin + if LastAtomWasSemicolon then begin + if length(SemicolonPositions)<=SemicolonCount then + SetLength(SemicolonPositions,length(SemicolonPositions)*2+2); + SemicolonPositions[SemicolonCount]:=AtomStart; + inc(SemicolonCount); + end; + LastAtomWasSemicolon:=true; + end else begin + LastAtomWasSemicolon:=false; + end; + until false; + + // build new source without semicolons + if SemicolonCount>0 then begin + SetLength(NewSrc,length(Source)-SemicolonCount); + AtomStart:=1; + i:=0; + while iAtomStart then + System.Move(Source[AtomStart],NewSrc[AtomStart-i],Position-AtomStart); + AtomStart:=Position+1; + inc(i); + end; + Position:=length(Source)+1; + if Position>AtomStart then + System.Move(Source[AtomStart],NewSrc[AtomStart-i],Position-AtomStart); + aText.Source:=NewSrc; + end; + + // clean up + Setlength(SemicolonPositions,0); + Result:=mrOk; +end; + end. diff --git a/components/h2pas/h2pasdlg.pas b/components/h2pas/h2pasdlg.pas index 9d134555f8..4aaf95db75 100644 --- a/components/h2pas/h2pasdlg.pas +++ b/components/h2pas/h2pasdlg.pas @@ -217,6 +217,7 @@ begin TextConverterToolClasses.RegisterClass(TConvertFunctionTypesToPointers); TextConverterToolClasses.RegisterClass(TPostH2PasTools); TextConverterToolClasses.RegisterClass(TReplaceUnitFilenameWithUnitName); + TextConverterToolClasses.RegisterClass(TRemoveDoubleSemicolons); TextConverterToolClasses.RegisterClass(TRemoveSystemTypes); TextConverterToolClasses.RegisterClass(TRemoveRedefinedPointerTypes); TextConverterToolClasses.RegisterClass(TRemoveEmptyTypeVarConstSections);