File: testchangedeclaration.pas

package info (click to toggle)
lazarus 4.0%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 275,760 kB
  • sloc: pascal: 2,341,904; xml: 509,420; makefile: 348,726; cpp: 93,608; sh: 3,387; java: 609; perl: 297; sql: 222; ansic: 137
file content (244 lines) | stat: -rw-r--r-- 8,429 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
unit TestChangeDeclaration;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils,
  LazLogger, LazFileUtils, fpcunit, testregistry, AVL_Tree,
  CodeToolManager, CodeCache, PascalParserTool, BasicCodeTools, CTUnitGraph,
  TestFinddeclaration, TestStdCodetools;

type

  { TTestChangeDeclaration }

  TTestChangeDeclaration = class(TCustomTestCTStdCodetools)
  protected
    FDefFilename: string;
    procedure SetUp; override;
    procedure TestRenameIdentifier(DeclCode: TCodeBuffer; SearchInCodeBufs: TFPList); overload;
    procedure TestRenameIdentifier(DeclCode: TCodeBuffer; Module1: TCodeBuffer = nil); overload;
  published
    procedure TestCTAddProcedureModifier;
    procedure TestCTRenameIdentifier_MultiInLine;
    procedure TestCTRenameIdentifier_MultiInLine_Amp;
  end;

implementation

procedure TTestChangeDeclaration.SetUp;
begin
  inherited SetUp;
  FDefFilename:='TestChangeDeclaration.pas';
end;

procedure TTestChangeDeclaration.TestRenameIdentifier(DeclCode: TCodeBuffer;
  SearchInCodeBufs: TFPList);
var
  p, DeclPos, l: SizeInt;
  NewIdentifier, OldIdentifier, Src, CurIdentifier: String;
  SearchInCode: TCodeBuffer;
  i, j: integer;
  DeclXY: TPoint;
  TreeOfPCodeXYPosition: TAVLTree;
  ListOfPCodeXYPosition: TFPList;
  Cache: TFindIdentifierReferenceCache;
  RefXYPos: TCodeXYPosition;
begin
  Cache:=nil;
  ListOfPCodeXYPosition:=nil;
  TreeOfPCodeXYPosition:=nil;
  try
    // parse %rename directive
    Src:=DeclCode.Source;
    DeclPos:=Pos('{%rename:',Src);
    if DeclPos<1 then
      Fail('missing declaration marker');
    inc(DeclPos,length('{%rename:'));
    NewIdentifier:=GetIdentifier(@Src[DeclPos]);
    if NewIdentifier='' then
      Fail('missing rename-to identifier');
    while Src[DeclPos]<>'}' do inc(DeclPos);
    inc(DeclPos);
    OldIdentifier:=GetIdentifier(@Src[DeclPos]);
    if OldIdentifier='' then
      Fail('missing rename-from identifier');

    DeclCode.AbsoluteToLineCol(DeclPos,DeclXY.Y,DeclXY.X);

    // find all references
    if SearchInCodeBufs=nil then
      SearchInCodeBufs:=TFPList.Create;
    if SearchInCodeBufs.IndexOf(DeclCode)<0 then
      SearchInCodeBufs.Add(DeclCode);
    for i:=0 to SearchInCodeBufs.Count-1 do begin
      SearchInCode:=TCodeBuffer(SearchInCodeBufs[i]);
      if not CodeToolBoss.FindReferences(DeclCode,DeclXY.X,DeclXY.Y,SearchInCode,false,ListOfPCodeXYPosition,Cache) then
        Fail('FindReferences failed at '+DeclCode.Filename+'('+dbgs(DeclXY.Y)+','+dbgs(DeclXY.X)+')');

      // check that all %R directives were found
      p:=1;
      Src:=SearchInCode.Source;
      l:=length(Src);
      while p<=l do begin
        if (Src[p]='{') and (Src[p+1]='%') and (Src[p+2]='R') and (Src[p+3]='}') then begin
          inc(p,4);
          RefXYPos.Code:=SearchInCode;
          SearchInCode.AbsoluteToLineCol(p,RefXYPos.Y,RefXYPos.X);
          j:=IndexOfCodePosition(ListOfPCodeXYPosition,@RefXYPos);
          if j<0 then begin
            if ListOfPCodeXYPosition=nil then
              debugln(['TTestChangeDeclaration.TestRenameIdentifier ListOfPCodeXYPosition empty'])
            else begin
              debugln(['TTestChangeDeclaration.TestRenameIdentifier ListOfPCodeXYPosition: Count=',ListOfPCodeXYPosition.Count]);
              for j:=0 to ListOfPCodeXYPosition.Count-1 do begin
                debugln(['  ',i,':',dbgs(PCodeXYPosition(ListOfPCodeXYPosition[j])^)]);
              end;
            end;
            Fail('missing reference: '+dbgs(RefXYPos));
          end;
        end else
          inc(p);
      end;

      // add to tree
      if ListOfPCodeXYPosition<>nil then begin
        if TreeOfPCodeXYPosition=nil then
          TreeOfPCodeXYPosition:=CodeToolBoss.CreateTreeOfPCodeXYPosition;
        CodeToolBoss.AddListToTreeOfPCodeXYPosition(ListOfPCodeXYPosition,
                                              TreeOfPCodeXYPosition,true,false); // this empties ListOfPCodeXYPosition
      end;
    end;

    if (TreeOfPCodeXYPosition=nil) or (TreeOfPCodeXYPosition.Count=0) then
      Fail('TreeOfPCodeXYPosition empty');

    // rename references
    if not CodeToolBoss.RenameIdentifier(TreeOfPCodeXYPosition,OldIdentifier,NewIdentifier,DeclCode,@DeclXY,false) then
      Fail('RenameIdentifier failed');

    // check all {%R} directives were replaced
    for i:=0 to SearchInCodeBufs.Count-1 do begin
      SearchInCode:=TCodeBuffer(SearchInCodeBufs[i]);
      // check that all %R directives were found
      p:=1;
      Src:=SearchInCode.Source;
      l:=length(Src);
      while p<=l do begin
        if (Src[p]='{') and (Src[p+1]='%') and (Src[p+2]='R') and (Src[p+3]='}') then begin
          inc(p,4);
          CurIdentifier:=copy(Src,p,length(NewIdentifier));
          if CurIdentifier<>NewIdentifier then
            Fail('reference differ: expected "'+NewIdentifier+'", but found "'+CurIdentifier+'"');
        end else
          inc(p);
      end;
    end;

  finally
    CodeToolBoss.FreeListOfPCodeXYPosition(ListOfPCodeXYPosition);
    CodeToolBoss.FreeTreeOfPCodeXYPosition(TreeOfPCodeXYPosition);
    Cache.Free;
    SearchInCodeBufs.Free;
  end;

end;

procedure TTestChangeDeclaration.TestRenameIdentifier(DeclCode: TCodeBuffer; Module1: TCodeBuffer);
var
  SearchInModules: TFPList;
begin
  SearchInModules:=TFPList.Create;
  if Module1<>nil then
    SearchInModules.Add(Module1);
  TestRenameIdentifier(DeclCode,SearchInModules);
end;

procedure TTestChangeDeclaration.TestCTAddProcedureModifier;

  procedure Test(ProcCode, aModifier, Expected: string);
  var
    Code: TCodeBuffer;
    Src, ProcHead: String;
  begin
    Src:='unit '+FDefFilename+';'+sLineBreak
      +'interface'+sLineBreak
      +ProcCode+sLineBreak
      +'implementation'+sLineBreak
      +'end.';
    Code:=CodeToolBoss.CreateFile(FDefFilename);
    Code.Source:=Src;
    if not CodeToolBoss.AddProcModifier(Code,3,3,aModifier) then
    begin
      Fail('AddProcModifier failed: '+CodeToolBoss.ErrorMessage);
    end else begin
      if not CodeToolBoss.ExtractProcedureHeader(Code,3,3,
        [phpWithStart,phpWithResultType,phpWithOfObject,phpWithProcModifiers,phpWithComments,phpDoNotAddSemicolon],
        ProcHead)
      then
        Fail('ExtractProcedureHeader failed: '+CodeToolBoss.ErrorMessage);
      if ProcHead<>Expected then begin
        writeln('Test ProcCode="',ProcCode,'"');
        Src:=Code.Source;
        writeln('SrcSTART:======================');
        writeln(Src);
        writeln('SrcEND:========================');
        AssertEquals('ProcHead',Expected,ProcHead);
      end;
    end;
  end;

begin
  // remove first unit
  Test('procedure DoIt;','overload','procedure DoIt; overload;');
  Test('procedure DoIt ;','overload','procedure DoIt; overload ;');
  Test('procedure DoIt ; ;','overload','procedure DoIt; overload ;');
  Test('procedure DoIt; overload;','overload','procedure DoIt; overload;');
  Test('procedure DoIt; {$IFDEF FPC}overload{$ENDIF};','overload','procedure DoIt; {$IFDEF FPC}overload{$ENDIF};');
  Test('procedure DoIt; procedure Bla;','overload','procedure DoIt; overload;');
  Test('  procedure DoIt;'+sLineBreak+'  procedure Bla;',
    'overload','procedure DoIt; overload;');
  Test('  procedure DoIt; external name ''doit'';'+sLineBreak+'  procedure Bla;',
    'overload','procedure DoIt; external name ''doit''; overload;');
end;

procedure TTestChangeDeclaration.TestCTRenameIdentifier_MultiInLine;
var
  DeclCode: TCodeBuffer;
begin
  DeclCode:=CodeToolBoss.CreateFile(FDefFilename);
  DeclCode.Source:='unit '+FDefFilename+';'+sLineBreak
    +'interface'+sLineBreak
    +'type'+sLineBreak
    +'  {%rename:TWhale}TFoo = word;'+sLineBreak
    +'  TBar = low({%R}TFoo)..high({%R}TFoo);'
    +'implementation'+sLineBreak
    +'type'+sLineBreak
    +'  TBird = low({%R}TFoo)..high({%R}TFoo);'
    +'end.';
  TestRenameIdentifier(DeclCode);
end;

procedure TTestChangeDeclaration.TestCTRenameIdentifier_MultiInLine_Amp;
var
  DeclCode: TCodeBuffer;
begin
  DeclCode:=CodeToolBoss.CreateFile(FDefFilename);
  DeclCode.Source:='unit '+FDefFilename+';'+sLineBreak
    +'interface'+sLineBreak
    +'type'+sLineBreak
    +'  {%rename:&Type}TFoo = word;'+sLineBreak
    +'  TBar = low({%R}TFoo)..high({%R}TFoo);'
    +'implementation'+sLineBreak
    +'type'+sLineBreak
    +'  TBird = low({%R}TFoo)..high({%R}TFoo);'
    +'end.';
  TestRenameIdentifier(DeclCode);
end;

initialization
  RegisterTests([TTestChangeDeclaration]);
end.