mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-22 13:59:31 +02:00
SynEdit: Markup-IfDef; fix crash. Issue: #0025811
git-svn-id: trunk@44345 -
This commit is contained in:
parent
3747f3f516
commit
f65306bccd
@ -1854,6 +1854,7 @@ var
|
||||
i, j, OtherDepth: Integer;
|
||||
OtherLine: TSynMarkupHighIfDefLinesNodeInfo;
|
||||
PeerChanged: Boolean;
|
||||
CurEntry: TSynMarkupHighIfDefEntry;
|
||||
|
||||
function OpenIdx(AIdx: Integer): Integer; // correct negative idx
|
||||
begin
|
||||
@ -1876,10 +1877,11 @@ begin
|
||||
SetLength(PeerList, MaxListIdx);
|
||||
|
||||
for i := 0 to ANode.EntryCount - 1 do begin
|
||||
case ANode.Entry[i].NodeType of
|
||||
CurEntry := ANode.Entry[i];
|
||||
case CurEntry.NodeType of
|
||||
idnIfdef: begin
|
||||
inc(CurDepth);
|
||||
OpenList[OpenIdx(CurDepth)] := ANode.Entry[i]; // Store IfDef, with Index at end of IfDef (inside block)
|
||||
OpenList[OpenIdx(CurDepth)] := CurEntry; // Store IfDef, with Index at end of IfDef (inside block)
|
||||
if CurDepth < MinOpenDepth then MinOpenDepth := CurDepth;
|
||||
if CurDepth > MaxOpenDepth then MaxOpenDepth := CurDepth;
|
||||
end;
|
||||
@ -1893,9 +1895,9 @@ begin
|
||||
assert(CurDepth = MaxOpenDepth, 'ConnectPeers: Same line peer skips opening node(s)');
|
||||
case OpenList[OpenIdx(CurDepth)].NodeType of
|
||||
idnIfdef, idnElseIf:
|
||||
if OpenList[OpenIdx(CurDepth)].ClosingPeer <> ANode.Entry[i] then begin
|
||||
if OpenList[OpenIdx(CurDepth)].ClosingPeer <> CurEntry then begin
|
||||
//Debugln(['New Peer for ',dbgs(OpenList[OpenIdx(CurDepth)].NodeType), ' to else same line']);
|
||||
OpenList[OpenIdx(CurDepth)].ClosingPeer := ANode.Entry[i];
|
||||
OpenList[OpenIdx(CurDepth)].ClosingPeer := CurEntry;
|
||||
PeerChanged := True;
|
||||
//dec(MaxOpenDepth); // Will be set with the current entry
|
||||
end;
|
||||
@ -1905,13 +1907,13 @@ begin
|
||||
else
|
||||
If CurDepth >= 0 then begin
|
||||
// Opening Node in previous line
|
||||
PeerList[CurDepth] := ANode.Entry[i];
|
||||
PeerList[CurDepth] := CurEntry;
|
||||
assert((MaxPeerDepth=-1) or ((MinPeerDepth <= MaxPeerDepth) and (CurDepth = MinPeerDepth-1)), 'ConnectPeers: skipped noeds during line scan');
|
||||
if CurDepth < MinPeerDepth then MinPeerDepth := CurDepth;
|
||||
if CurDepth > MaxPeerDepth then MaxPeerDepth := CurDepth;
|
||||
end;
|
||||
|
||||
OpenList[OpenIdx(CurDepth)] := ANode.Entry[i]; // Store IfDef, with Index at end of IfDef (inside block)
|
||||
OpenList[OpenIdx(CurDepth)] := CurEntry; // Store IfDef, with Index at end of IfDef (inside block)
|
||||
if CurDepth < MinOpenDepth then MinOpenDepth := CurDepth;
|
||||
if CurDepth > MaxOpenDepth then MaxOpenDepth := CurDepth;
|
||||
end;
|
||||
@ -1925,16 +1927,16 @@ begin
|
||||
if (CurDepth >= MinOpenDepth) and (CurDepth <= MaxOpenDepth) then begin
|
||||
// Opening Node on this line
|
||||
assert(CurDepth = MaxOpenDepth, 'ConnectPeers: Same line peer skips opening node(s)');
|
||||
if OpenList[OpenIdx(CurDepth)].ClosingPeer <> ANode.Entry[i] then begin
|
||||
if OpenList[OpenIdx(CurDepth)].ClosingPeer <> CurEntry then begin
|
||||
//Debugln(['New Peer for ',dbgs(OpenList[OpenIdx(CurDepth)].NodeType), ' to endif same line']);
|
||||
OpenList[OpenIdx(CurDepth)].ClosingPeer := ANode.Entry[i];
|
||||
OpenList[OpenIdx(CurDepth)].ClosingPeer := CurEntry;
|
||||
PeerChanged := True;
|
||||
end;
|
||||
dec(MaxOpenDepth);
|
||||
end
|
||||
else begin
|
||||
// Opening Node in previous line
|
||||
PeerList[CurDepth] := ANode.Entry[i];
|
||||
PeerList[CurDepth] := CurEntry;
|
||||
assert((MaxPeerDepth=-1) or ((MinPeerDepth <= MaxPeerDepth) and (CurDepth = MinPeerDepth-1)), 'ConnectPeers: skipped noeds during line scan');
|
||||
if CurDepth < MinPeerDepth then MinPeerDepth := CurDepth;
|
||||
if CurDepth > MaxPeerDepth then MaxPeerDepth := CurDepth;
|
||||
@ -1957,18 +1959,22 @@ begin
|
||||
//end;
|
||||
|
||||
assert(not (PeerList[i].NodeType in [idnIfdef, idnCommentedNode]), 'multi-line peer valid');
|
||||
//if (PeerList[i].NodeType = idnElse) and (AOuterLines <> nil) then begin
|
||||
|
||||
// AOuterLines is only set while scanning opening lines in front of the 1st visible screenline
|
||||
// (at the start of ValidateRange)
|
||||
if (AOuterLines <> nil) then begin
|
||||
// todo: find multiply elseif
|
||||
assert((PeerList[i].NodeType in [idnElse, idnElseIf]), 'multi-line (opening) peer valid');
|
||||
// scanning outer lines
|
||||
j := ToPos(AOuterLines.NodeLineEx[i-1, 1]);
|
||||
if j < 0 then begin
|
||||
//debugln(['Skipping peer for ELSE with NO IFDEF at depth ', i-1, ' before line ', ANode.StartLine]);
|
||||
continue;
|
||||
end;
|
||||
OtherLine := GetOrInsertNodeAtLine(j);
|
||||
MaybeValidateNode(OtherLine);
|
||||
if PeerList[i].NodeType in [idnElse, idnElseIf] then begin
|
||||
// todo: find multiply elseif
|
||||
j := ToPos(AOuterLines.NodeLineEx[i-1, 1]);
|
||||
if j < 0 then begin
|
||||
//debugln(['Skipping peer for ELSE with NO IFDEF at depth ', i-1, ' before line ', ANode.StartLine]);
|
||||
continue;
|
||||
end;
|
||||
OtherLine := GetOrInsertNodeAtLine(j);
|
||||
MaybeValidateNode(OtherLine);
|
||||
end
|
||||
else
|
||||
continue; // while scanning outerlines, any EndIf can be ignored
|
||||
end
|
||||
else
|
||||
OtherLine := ANestList.Node[i]; // Todo: keep if same al last loop, and continue at OtherDepth / j
|
||||
|
@ -58,6 +58,8 @@ type
|
||||
function TestText9: TStringArray;
|
||||
function TestText10: TStringArray;
|
||||
function TestText11: TStringArray;
|
||||
function TestText11a: TStringArray;
|
||||
function TestText12: TStringArray;
|
||||
|
||||
procedure CheckOpenCloseCount(AName: String; ALine: Integer;
|
||||
AExpOpenCnt, AExpCloseCnt: Integer);
|
||||
@ -705,6 +707,83 @@ begin
|
||||
|
||||
end;
|
||||
|
||||
function TTestMarkupIfDef.TestText11a: TStringArray;
|
||||
procedure AddLine(s: String);
|
||||
begin
|
||||
SetLength(Result, Length(Result)+1);
|
||||
Result[Length(Result)-1] := s;
|
||||
end;
|
||||
begin
|
||||
// 1
|
||||
AddLine('{$if defined(cpu86)}' ); // level 0
|
||||
AddLine(' {$if defined(cpu86)} '); // level 1
|
||||
AddLine(' // a');
|
||||
AddLine(' {$elseif defined(cpupowerpc)} '); // level 1
|
||||
//5
|
||||
AddLine(' // disabled ');
|
||||
AddLine(' {$elseif defined(cpupowerpc)} '); // level 1
|
||||
AddLine(' // enabled (invalid) ');
|
||||
AddLine(' {$elseif defined(cpuarm)} '); // level 1
|
||||
AddLine(' {$if defined(cpu86)}// enabled (invalid) ');
|
||||
// 10
|
||||
AddLine(' {$ifend}{$if defined(cpu86)}' ); // level 2
|
||||
AddLine(' {$ifend}{$elseif defined(CPUX86_64)} '); // level 1 (close lvl 2)
|
||||
AddLine(' // enabled (invalid) ');
|
||||
AddLine(' {$if defined(cpu86)}' ); // level 2
|
||||
AddLine(' {$ifend}{$if defined(cpu86)}' ); // level 2 <> 2
|
||||
// 15
|
||||
AddLine(' // nested ');
|
||||
AddLine(' {$elseif defined(cpuarm)} '); // level 2
|
||||
AddLine(' // nested ');
|
||||
AddLine(' {$else} '); // level 2
|
||||
AddLine(' // nested ');
|
||||
// 20
|
||||
AddLine(' {$ifend} '); // level 2
|
||||
AddLine(' {$else} '); // level 1
|
||||
AddLine(' // enabled (invalid) ');
|
||||
AddLine(' {$if defined(cpu86)}' );
|
||||
AddLine(' // nested ');
|
||||
// 25
|
||||
AddLine(' {$ifend}{$if defined(cpu86)}' );
|
||||
AddLine(' // nested ');
|
||||
AddLine(' {$elseif defined(cpuarm)} ');
|
||||
AddLine(' // nested ');
|
||||
AddLine(' {$else} ');
|
||||
// 30
|
||||
AddLine(' // nested ');
|
||||
AddLine(' {$ifend} ');
|
||||
AddLine(' {$ifend} ');
|
||||
AddLine('' );
|
||||
AddLine(' {$ifend} ');
|
||||
// 35
|
||||
AddLine('' );
|
||||
AddLine('' );
|
||||
AddLine('' );
|
||||
end;
|
||||
|
||||
function TTestMarkupIfDef.TestText12: TStringArray;
|
||||
procedure AddLine(s: String);
|
||||
begin
|
||||
SetLength(Result, Length(Result)+1);
|
||||
Result[Length(Result)-1] := s;
|
||||
end;
|
||||
begin
|
||||
// 1
|
||||
AddLine('program project1;');
|
||||
AddLine('');
|
||||
AddLine('{$mode objfpc}{$H+}');
|
||||
AddLine('');
|
||||
// 5
|
||||
AddLine('uses {$IFDEF UNIX} {$IFDEF UseCThreads}');
|
||||
AddLine(' cthreads, {$ENDIF} {$ENDIF} {$ifdef LCLWinCE}');
|
||||
AddLine(' WinCEInt, {$endif}');
|
||||
AddLine(' Interfaces, // this includes the LCL widgetset');
|
||||
AddLine(' Windows,');
|
||||
AddLine(' SysUtils,');
|
||||
AddLine(' Forms;');
|
||||
AddLine('');
|
||||
end;
|
||||
|
||||
procedure TTestMarkupIfDef.CheckOpenCloseCount(AName: String; ALine: Integer; AExpOpenCnt,
|
||||
AExpCloseCnt: Integer);
|
||||
var
|
||||
@ -2030,6 +2109,62 @@ procedure TTestMarkupIfDef.TestIfDefTreePeerConnect;
|
||||
|
||||
{%endregion }
|
||||
|
||||
{%region }
|
||||
for i := 1 to 34 do begin
|
||||
n := 'TestText11a elseif ' + IntToStr(i);
|
||||
ReCreateEditForTreeTest(TestText11a);
|
||||
FTestTree.ValidateRange(i, 35, FOpenings);
|
||||
|
||||
n := 'TestText11a elseif ' + IntToStr(i);
|
||||
ReCreateEditForTreeTest(TestText11a);
|
||||
FTestTree.ValidateRange(i, i+1, FOpenings);
|
||||
|
||||
n := 'TestText11a elseif ' + IntToStr(i);
|
||||
ReCreateEditForTreeTest(TestText11a);
|
||||
FTestTree.ValidateRange(i, i+2, FOpenings);
|
||||
end;
|
||||
|
||||
n := 'TestText11a elseif 12-30';
|
||||
ReCreateEditForTreeTest(TestText11a);
|
||||
FTestTree.ValidateRange(11, 30, FOpenings);
|
||||
CheckNodes(n, 1, [ ExpN( 1,21, idnIfdef)]);
|
||||
//CheckNodes(n, 2, [ ExpN( 1,21, idnIfdef)]);
|
||||
CheckNodes(n, 11, [ ExpN( 3,11, idnEndIf, EpIf(10,13), EpNil),
|
||||
ExpN(11,39, idnElseIf, EpElseIf(8, 3), EpElse(21,3)) ]);
|
||||
{%endregion }
|
||||
|
||||
{%region issue 0025811 }
|
||||
|
||||
n := 'issue 0025811';
|
||||
ReCreateEditForTreeTest(TestText12);
|
||||
FTestTree.ValidateRange( 7, 10, FOpenings);
|
||||
CheckNodes(n, 6, [ ExpN( 13,21, idnSkipTest), ExpN(22,30, idnSkipTest),
|
||||
ExpN(31, 48, idnIfdef, EpNil, EpEnd(7, 13)) ]);
|
||||
CheckNodes(n, 7, [ ExpN( 13,21, idnEndIf, EpIf(6, 31), EpNil) ]);
|
||||
|
||||
ReCreateEditForTreeTest(TestText12);
|
||||
FTestTree.ValidateRange( 5, 10, FOpenings);
|
||||
CheckNodes(n, 5, [ ExpN( 6,19, idnIfdef, EpNil, EpEnd(6,22)),
|
||||
ExpN(20,40, idnIfdef, EpNil, EpEnd(6,13)) ]);
|
||||
CheckNodes(n, 6, [ ExpN(13,21, idnEndIf, EpIf(5,20), EpNil),
|
||||
ExpN(22,30, idnEndIf, EpIf(5, 6), EpNil),
|
||||
ExpN(31, 48, idnIfdef, EpNil, EpEnd(7, 13)) ]);
|
||||
CheckNodes(n, 7, [ ExpN( 13,21, idnEndIf, EpIf(6, 31), EpNil) ]);
|
||||
|
||||
ReCreateEditForTreeTest(TestText12);
|
||||
FTestTree.ValidateRange( 6, 10, FOpenings);
|
||||
CheckNodes(n, 5, [ ExpN( 6,19, idnIfdef, EpNil, EpEnd(6,22)),
|
||||
ExpN(20,40, idnIfdef, EpNil, EpEnd(6,13)) ]);
|
||||
CheckNodes(n, 6, [ ExpN(13,21, idnEndIf, EpIf(5,20), EpNil),
|
||||
ExpN(22,30, idnEndIf, EpIf(5, 6), EpNil),
|
||||
ExpN(31, 48, idnIfdef, EpNil, EpEnd(7, 13)) ]);
|
||||
CheckNodes(n, 7, [ ExpN( 13,21, idnEndIf, EpIf(6, 31), EpNil) ]);
|
||||
|
||||
ReCreateEditForTreeTest(TestText12);
|
||||
FTestTree.ValidateRange( 8, 10, FOpenings);
|
||||
|
||||
{%endregion }
|
||||
|
||||
|
||||
|
||||
FTestTree.DiscardOpeningList(FOpenings);
|
||||
@ -2059,7 +2194,7 @@ begin
|
||||
else
|
||||
Result := TSynMarkupIfdefNodeState(StrToIntDef(v, 0));
|
||||
|
||||
DebugLn('# TesTNodeStateHandler ', n, ' # ', v, ' ', dbgs(Result));
|
||||
//DebugLn('# TesTNodeStateHandler ', n, ' # ', v, ' ', dbgs(Result));
|
||||
end;
|
||||
|
||||
procedure TTestMarkupIfDef.TestIfDefTreeNodeState;
|
||||
@ -2258,8 +2393,8 @@ FTestTree.DebugPrint(true);DebugLn('-----');
|
||||
|
||||
//SynEdit.TextBetweenPoints[point( 7,3),point( 1,4)] := ''; // JOIN LINES
|
||||
SynEdit.TestTypeText(1, 4, #8, true);
|
||||
|
||||
|
||||
|
||||
|
||||
FTestTree.ValidateRange( 1, 16, FOpenings);
|
||||
FTestTree.SetNodeState( 2, 3, idnEnabled);
|
||||
//FTestTree.SetNodeState( 4, 3, idnDisabled);
|
||||
@ -2292,7 +2427,6 @@ DebugLn('----- disabled');FTestTree.DebugPrint(true);DebugLn('-----');
|
||||
|
||||
|
||||
|
||||
|
||||
FTestTree.DiscardOpeningList(FOpenings);
|
||||
FOpenings := nil;
|
||||
FTestTree.Free;
|
||||
|
Loading…
Reference in New Issue
Block a user