From a8d568ef5502dc018e8bcd490418c894bcf604e0 Mon Sep 17 00:00:00 2001 From: Martin Date: Sun, 1 May 2022 18:31:37 +0200 Subject: [PATCH] SynEdit: fix PasHighLighter for "default" modifier after property. (fix false matches). Issue #39726 (cherry picked from commit db98b760768555d14fb866cc8c7917c43a0d98f2) --- components/synedit/synhighlighterpas.pp | 40 +++++++-- .../synedit/test/testhighlightfoldbase.pas | 4 +- components/synedit/test/testhighlightpas.pas | 90 +++++++++++++++++++ 3 files changed, 126 insertions(+), 8 deletions(-) diff --git a/components/synedit/synhighlighterpas.pp b/components/synedit/synhighlighterpas.pp index 467a036c80..01e8178d91 100644 --- a/components/synedit/synhighlighterpas.pp +++ b/components/synedit/synhighlighterpas.pp @@ -1346,8 +1346,12 @@ begin begin if (fRange * [rsProperty, rsAtPropertyOrReadWrite, rsAfterEqualOrColon] = [rsProperty]) and (PasCodeFoldRange.BracketNestLevel = 0) - then - Result := tkKey else Result := tkIdentifier; + then begin + Result := tkKey; + fRange := fRange + [rsAtPropertyOrReadWrite]; + end + else + Result := tkIdentifier; end else if KeyComp('Out') then Result := tkKey else Result := tkIdentifier; @@ -1492,8 +1496,18 @@ end; function TSynPasSyn.Func69: TtkTokenKind; begin if KeyComp('Default') then begin - if (TopPascalCodeFoldBlockType in [cfbtClass, cfbtClassSection, cfbtRecord]) then - Result := tkKey + if (PasCodeFoldRange.BracketNestLevel = 0) and + (fRange * [rsAtPropertyOrReadWrite, rsAfterEqualOrColon, rsInProcHeader] = []) and + ( ( (TopPascalCodeFoldBlockType in [cfbtClass, cfbtClassSection, cfbtRecord]) and + (rsAfterClassMembers in fRange) + ) or + (rsProperty in fRange) + ) + then begin + Result := tkKey; + if rsProperty in fRange then + fRange := fRange + [rsAtPropertyOrReadWrite]; + end else Result := tkIdentifier; end else @@ -2842,7 +2856,9 @@ begin fTokenID := tkSymbol; inc(Run); if fLine[Run] = '=' then - inc(Run) + inc(Run); + if rsProperty in fRange then + fRange := fRange + [rsAtPropertyOrReadWrite]; end; procedure TSynPasSyn.CRProc; @@ -2909,6 +2925,8 @@ begin fTokenID := tkSymbol; inc(Run); if fLine[Run] in ['=', '>'] then inc(Run); + if rsProperty in fRange then + fRange := fRange + [rsAtPropertyOrReadWrite]; end; procedure TSynPasSyn.CaretProc; @@ -2974,7 +2992,11 @@ procedure TSynPasSyn.PointProc; begin fTokenID := tkSymbol; inc(Run); - if fLine[Run] in ['.', ')'] then inc(Run); + if fLine[Run] in ['.', ')'] then + inc(Run) + else + if fRange * [rsProperty, rsAfterClassMembers] <> [] then // Also happens for result-type of functions (if they have a dot) + fRange := fRange + [rsAtPropertyOrReadWrite]; end; procedure TSynPasSyn.AnsiProc; @@ -3079,6 +3101,8 @@ begin not(rsAfterClassMembers in fRange) then fRange := fRange + [rsVarTypeInSpecification]; + if rsProperty in fRange then + fRange := fRange + [rsAtPropertyOrReadWrite]; end; procedure TSynPasSyn.SemicolonProc; @@ -3136,6 +3160,8 @@ begin end else begin Inc(Run); fTokenID := tkSymbol; + if rsProperty in fRange then + fRange := fRange + [rsAtPropertyOrReadWrite]; end; end; @@ -3191,6 +3217,8 @@ procedure TSynPasSyn.SymbolProc; begin inc(Run); fTokenID := tkSymbol; + if rsProperty in fRange then + fRange := fRange + [rsAtPropertyOrReadWrite]; end; function TSynPasSyn.TypeHelpersIsStored: Boolean; diff --git a/components/synedit/test/testhighlightfoldbase.pas b/components/synedit/test/testhighlightfoldbase.pas index e60fe62cce..9e2d5a4c40 100644 --- a/components/synedit/test/testhighlightfoldbase.pas +++ b/components/synedit/test/testhighlightfoldbase.pas @@ -213,9 +213,9 @@ begin e := ExpTokens[c]; //DebugLn([FTheHighLighter.GetToken,' (',FTheHighLighter.GetTokenKind ,') at ', FTheHighLighter.GetTokenPos]); if etiKind in e.Flags then - AssertEquals(Name + ' Kind @ TokenId Line='+IntToStr(LineIdx)+' pos='+IntToStr(c), e.ExpKind, FTheHighLighter.GetTokenKind); + AssertEquals(Name + ' Kind @ TokenId Line='+IntToStr(LineIdx)+' pos='+IntToStr(c)+'Src='+FTheHighLighter.GetToken+' @'+IntToStr(FTheHighLighter.GetTokenPos), e.ExpKind, FTheHighLighter.GetTokenKind); if etiAttr in e.Flags then - AssertEquals(Name + ' Attr @ TokenId Line='+IntToStr(LineIdx)+' pos='+IntToStr(c), AttrVal(e.ExpAttr), AttrVal(FTheHighLighter.GetTokenAttribute)); + AssertEquals(Name + ' Attr @ TokenId Line='+IntToStr(LineIdx)+' pos='+IntToStr(c)+'Src='+FTheHighLighter.GetToken+' @'+IntToStr(FTheHighLighter.GetTokenPos), AttrVal(e.ExpAttr), AttrVal(FTheHighLighter.GetTokenAttribute)); FTheHighLighter.Next; inc(c); diff --git a/components/synedit/test/testhighlightpas.pas b/components/synedit/test/testhighlightpas.pas index e8b5abf771..9db76ea8f1 100644 --- a/components/synedit/test/testhighlightpas.pas +++ b/components/synedit/test/testhighlightpas.pas @@ -68,6 +68,14 @@ type implementation +const + TK_Comma = tkSymbol; + TK_Semi = tkSymbol; + TK_Dot = tkSymbol; + TK_Colon = tkSymbol; + TK_Equal = tkSymbol; + TK_Bracket = tkSymbol; + operator := (a: TtkTokenKind) : TExpTokenInfo; begin result := default(TExpTokenInfo); @@ -660,6 +668,88 @@ begin tkSymbol ]); {%endregion} + + {%region property and default} + ReCreateEdit; + SetLines + ([ 'Unit A; interface', + 'type TFoo = class', + 'default,default:default;', + 'private type', + 'default=integer;', + 'private', + 'a: default;', + 'default:default.default;', + {8} 'function default(default:default):default;', + {9} 'function default(default:default.default):default.default;', +{10} 'property default[default:default]:default read default write default; default;', +{11} 'property default:default read default default default;', +{12} 'property default:default index default read default default default-default+default;', + // property could read a field inside an embedded record +{13} 'property default:default.default index {C} default.default read {C} default.default {C} default default.default * default.default;', + '' + ]); + + CheckTokensForLine('FIELD: default,default:default;', 2, + [ tkIdentifier, TK_Comma, tkIdentifier, // default , default + TK_Colon, tkIdentifier, TK_Semi // : default; + ]); + + CheckTokensForLine('TYPE: default=integer;', 4, + [ tkIdentifier, TK_Equal, tkIdentifier, TK_Semi // default = integer ; + ]); + + CheckTokensForLine('FIELD: default:default.default;', 7, + [ tkIdentifier, TK_Colon, tkIdentifier, TK_Dot, tkIdentifier, TK_Semi // default : default . default ; + ]); + + CheckTokensForLine('function default(default:default):default;', 8, + [ tkKey, tkSpace, tkIdentifier, // function default + TK_Bracket, tkIdentifier, TK_Colon, tkIdentifier, TK_Bracket, // ( default : default ) + TK_Colon, tkIdentifier, TK_Semi // : default; + ]); + + CheckTokensForLine('function default(default:default.default):default.default;', 9, + [ tkKey, tkSpace, tkIdentifier, // function default + TK_Bracket, tkIdentifier, TK_Colon, // ( default : + tkIdentifier, TK_Dot, tkIdentifier, TK_Bracket, // default . default ) + TK_Colon, tkIdentifier, TK_Dot, tkIdentifier, TK_Semi // : default . default; + ]); + + CheckTokensForLine('property default[default:default]:default read default write default; default;', 10, + [ tkKey, tkSpace, tkIdentifier, TK_Bracket, tkIdentifier, // property default[default + TK_Colon, tkIdentifier, TK_Bracket, TK_Colon, tkIdentifier, // :default]:default + tkSpace, tkKey, tkSpace, tkIdentifier, // read default + tkSpace, tkKey, tkSpace, tkIdentifier, // write default + TK_Semi, tkSpace, tkKey, TK_Semi // ; default; + ]); + + CheckTokensForLine('property default:default read default default default;', 11, + [ tkKey, tkSpace, tkIdentifier, TK_Colon, tkIdentifier, //property default:default + tkSpace, tkKey, tkSpace, tkIdentifier, // read default + tkSpace, tkKey, tkSpace, tkIdentifier, TK_Semi // default default; + ]); + + CheckTokensForLine('property default:default index default read default default default-default+default;', 12, + [ tkKey, tkSpace, tkIdentifier, TK_Colon, tkIdentifier, // property default:default + tkSpace, tkKey, tkSpace, tkIdentifier, // index default + tkSpace, tkKey, tkSpace, tkIdentifier, // read default + tkSpace, tkKey, tkSpace, tkIdentifier, // default default + tkSymbol, tkIdentifier, tkSymbol, tkIdentifier, TK_Semi // -default+default; + ]); + + CheckTokensForLine('property default:default.default index {C} default.default read {C} default.default {C} default default.default * default.default;', 13, + [ tkKey, tkSpace, tkIdentifier, TK_Colon, tkIdentifier, TK_Dot, tkIdentifier, // property default:default.default + tkSpace, tkKey, tkSpace, tkComment, tkSpace, // index (C} + tkIdentifier, TK_Dot, tkIdentifier, tkSpace, // default.default + tkKey, tkSpace, tkComment, tkSpace, // read (C} + tkIdentifier, TK_Dot, tkIdentifier, tkSpace, // default.default + tkComment, tkSpace, // (C} + tkKey, tkSpace, tkIdentifier, TK_Dot, tkIdentifier, tkSpace, // default default.default + tkSymbol, tkSpace, tkIdentifier, TK_Dot, tkIdentifier, TK_Semi // * default.default; + ]); + + {%endregion} end; procedure TTestHighlighterPas.TestContextForProcedure;