SynEdit: Markup-IfDef; fix crash. Issue: #0025811

git-svn-id: trunk@44345 -
This commit is contained in:
martin 2014-03-04 19:22:38 +00:00
parent 3747f3f516
commit f65306bccd
2 changed files with 164 additions and 24 deletions

View File

@ -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

View File

@ -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;