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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424 | --
-- Copyright (C) 2022-2023, AdaCore
--
-- SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
--
with Langkit_Support.Errors;
with Libadalang.Common;
with Ada.Containers.Vectors;
with Ada.Strings;
with Ada.Characters.Latin_1;
with Langkit_Support.Text;
with LAL_Refactor.Subprogram_Signature;
with LAL_Refactor.Subprogram_Signature.Remove_Parameter;
with LAL_Refactor.Output;
package body LAL_Refactor.Tools.Suppress_Dead_Params_Tool is
package LALCO renames Libadalang.Common;
package Text renames Langkit_Support.Text;
package Range_Vectors is new Ada.Containers.Vectors
(Index_Type => Positive,
Element_Type => ReFac.Subprogram_Signature.Parameter_Indices_Range_Type,
"=" => ReFac.Subprogram_Signature."="
);
---------
-- "<" --
---------
function "<" (L, R : LAL.Defining_Name) return Boolean is
begin
if L.Unit.Get_Filename < R.Unit.Get_Filename then
return True;
else
if L.Unit.Get_Filename > R.Unit.Get_Filename then
return False;
else
return (Start_Sloc (LAL.Sloc_Range (L)) <
Start_Sloc (LAL.Sloc_Range (R)));
end if;
end if;
end "<";
------------------------
-- Find_Useless_Param --
------------------------
function Find_Dead_Param (Unit_Array : LAL.Analysis_Unit_Array)
return Edit_Infos is
Any_Value : constant Value := (Fixed => False);
Vals : Values.Map;
Edit_Infos : Subp_Spec_To_Edit_Text.Map;
Subpspec_To_Param : Subp_Spec_To_Defining_Names_Set.Map;
procedure Add_Value
(S : LAL.Subp_Spec;
N : LAL.Defining_Name;
E : LAL.Enum_Literal_Decl);
-- Add the called value to the relative subprogram
procedure Add_Any_Value
(S : LAL.Subp_Spec;
N : LAL.Defining_Name);
-- Erase any fixed enumeration value associated to N
procedure Safe_Insert
(Params : in out Defining_Name_Ordered_Sets.Set;
Param : LAL.Defining_Name);
-- Insert Removable Parameter's name to the Set
procedure Safe_Insert
(Edits : in out Subp_Spec_To_Defining_Names_Set.Map;
Func_Name : LAL.Subp_Spec;
Param : LAL.Defining_Name);
-- Insert Removable Parameter's name to the Map
procedure Visit_Subp_Spec (Node : LAL.Subp_Spec);
-- Handle a subprogram spec for the canonical declaration of a
-- subprogram, which can be its spec or its body. For every default
-- value of a parameter of an enumeration type, consider that there is
-- a call with that default value, and treat it similarly.
function Find_Subprogram (Node : LAL.Ada_Node'Class)
return LALCO.Visit_Status;
-- travers all the AST and find out all the Supb_Spec
function Get_Enumeration_Literal (Node : LAL.Expr'Class)
return LAL.Enum_Literal_Decl;
-- if the subprogram is called by a enumerate type, return it.
procedure Generate_Edits (Func_Name : LAL.Subp_Spec);
-- Value E was observed for parameter N
---------------
-- Add_Value --
---------------
procedure Add_Value
(S : LAL.Subp_Spec;
N : LAL.Defining_Name;
E : LAL.Enum_Literal_Decl) is
V : constant Value := (True, E);
C : Values.Cursor;
R : Boolean;
begin
Vals.Insert (Key => N, New_Item => V, Position => C, Inserted => R);
Safe_Insert (Subpspec_To_Param, S, N);
if not R
and then Vals (C) /= V
then
Vals.Include (Key => N, New_Item => Any_Value);
if Subpspec_To_Param.Contains (S) then
Subpspec_To_Param (S).Exclude (N);
end if;
end if;
end Add_Value;
-------------------
-- Add_Any_Value --
-------------------
procedure Add_Any_Value
(S : LAL.Subp_Spec;
N : LAL.Defining_Name)
is
begin
Vals.Include (Key => N, New_Item => Any_Value);
if Subpspec_To_Param.Contains (S) then
Subpspec_To_Param (S).Exclude (N);
end if;
end Add_Any_Value;
-----------------
-- Safe_Insert --
-----------------
procedure Safe_Insert
(Params : in out Defining_Name_Ordered_Sets.Set;
Param : LAL.Defining_Name) is
begin
if not Params.Contains (Param) then
Params.Insert (Param);
end if;
end Safe_Insert;
-----------------
-- Safe_Insert --
-----------------
procedure Safe_Insert
(Edits : in out Subp_Spec_To_Defining_Names_Set.Map;
Func_Name : LAL.Subp_Spec;
Param : LAL.Defining_Name) is
Edits_Set : Defining_Name_Ordered_Sets.Set;
begin
if Edits.Contains (Func_Name) then
Safe_Insert (Edits.Reference (Func_Name), Param);
else
Edits_Set.Insert (Param);
Edits.Insert (Func_Name, Edits_Set);
end if;
end Safe_Insert;
-----------------------------
-- Get_Enumeration_Literal --
-----------------------------
function Get_Enumeration_Literal (Node : LAL.Expr'Class)
return LAL.Enum_Literal_Decl is
begin
if Node.Kind in LALCO.Ada_Identifier_Range
and then not Node.As_Identifier.P_Referenced_Decl.Is_Null
and then Node.As_Identifier.P_Referenced_Decl.Kind
in LALCO.Ada_Enum_Literal_Decl_Range
then
return Node.As_Identifier.P_Referenced_Decl.As_Enum_Literal_Decl;
else
return LAL.No_Enum_Literal_Decl;
end if;
end Get_Enumeration_Literal;
---------------------
-- Visit_Subp_Spec --
---------------------
procedure Visit_Subp_Spec (Node : LAL.Subp_Spec) is
begin
if not Node.As_Subp_Spec.F_Subp_Params.Is_Null then
declare
Params : constant LAL.Param_Spec_List :=
Node.As_Subp_Spec.F_Subp_Params.F_Params;
begin
for Param of Params loop
declare
Default : constant LAL.Expr'Class :=
Param.As_Param_Spec.F_Default_Expr;
begin
if not Default.Is_Null then
if not Get_Enumeration_Literal (Default).Is_Null then
for P of Param.As_Param_Spec.F_Ids loop
Add_Value (Node,
P.As_Defining_Name,
Get_Enumeration_Literal (Default));
end loop;
elsif not Default.P_Expression_Type.Is_Null
and then Default.P_Expression_Type.P_Is_Enum_Type
then
for P of Param.As_Param_Spec.F_Ids loop
Add_Any_Value (Node, P.As_Defining_Name);
end loop;
end if;
end if;
end;
end loop;
end;
end if;
end Visit_Subp_Spec;
-----------
-- Visit --
-----------
function Find_Subprogram (Node : LAL.Ada_Node'Class)
return LALCO.Visit_Status is
begin
case Node.Kind is
when LALCO.Ada_Subp_Spec_Range =>
if Node.Parent.Kind not in LALCO.Ada_Subp_Body_Range then
Visit_Subp_Spec (Node.As_Subp_Spec);
end if;
when LALCO.Ada_Call_Expr =>
declare
Call : constant LAL.Call_Expr'Class := Node.As_Call_Expr;
begin
if Call.F_Suffix.Kind in LALCO.Ada_Assoc_List_Range then
declare
Params : constant LAL.Param_Actual_Array :=
Call.F_Suffix.As_Assoc_List.P_Zip_With_Params;
begin
for Pair of Params loop
declare
P : constant LAL.Defining_Name'Class :=
LAL.Param (Pair).P_Canonical_Part;
A : constant LAL.Expr'Class := LAL.Actual (Pair);
begin
if not Get_Enumeration_Literal (A).Is_Null then
Add_Value (Call.P_Called_Subp_Spec.As_Subp_Spec,
P.As_Defining_Name
, Get_Enumeration_Literal (A));
elsif P.F_Name.P_Is_Constant
then
Add_Value (Call.P_Called_Subp_Spec.As_Subp_Spec,
P.As_Defining_Name,
P.As_Defining_Name.F_Name
.P_Referenced_Decl
.As_Object_Decl.F_Default_Expr
.As_Enum_Literal_Decl);
elsif not A.P_Expression_Type.Is_Null
and then A.P_Expression_Type.P_Is_Enum_Type
then
Add_Any_Value (Call.P_Called_Subp_Spec
.As_Subp_Spec,
P.As_Defining_Name);
end if;
end;
end loop;
end;
end if;
exception
-- due to null dereference during P_Zip_With_Params
-- as well as timeout
when Langkit_Support.Errors.Property_Error => null;
end;
when others =>
null;
end case;
return LALCO.Into;
end Find_Subprogram;
--------------------
-- Generate_Edits --
--------------------
procedure Generate_Edits (Func_Name : LAL.Subp_Spec) is
Param_Removable : constant Defining_Name_Ordered_Sets.Set :=
Subpspec_To_Param (Func_Name);
Param_Indices : Range_Vectors.Vector;
Params : constant LAL.Param_Spec_Array :=
Func_Name.P_Params;
Flag : Boolean := False;
First, Last : Positive := 1;
Indice_Range : ReFac.Subprogram_Signature.
Parameter_Indices_Range_Type;
Father : constant LAL.Ada_Node := Func_Name.Parent;
function Generate_Constant return ReFac.Text_Edit;
-- generate the text_edit for each dead parameters
-----------------------
-- Generate_Constant --
-----------------------
function Generate_Constant return ReFac.Text_Edit is
Define_Text : Ada.Strings.Unbounded.Unbounded_String :=
Ada.Strings.Unbounded.Null_Unbounded_String;
Text_Edit : ReFac.Text_Edit;
Position : constant Source_Location_Range := Func_Name.Sloc_Range;
procedure Generate_Text;
-- generate the declaration of the dead parameters
-------------------
-- Generate_Text --
-------------------
procedure Generate_Text is
begin
for Param of Param_Removable loop
Define_Text := Define_Text
& Text.Image (Param.P_Basic_Decl.Text);
if Param.P_Basic_Decl.As_Param_Spec.F_Default_Expr.Is_Null
then
Define_Text := Define_Text & " := "
& Text.Image (Vals (Param).V.Text);
end if;
Define_Text := Define_Text & ";";
end loop;
Define_Text := Define_Text & Ada.Characters.Latin_1.LF;
end Generate_Text;
begin
if Father.Kind in LALCO.Ada_Subp_Body_Range then
Text_Edit.Location.Start_Column := Position.Start_Column + 3;
Text_Edit.Location.End_Column := Position.Start_Column + 3;
Text_Edit.Location.Start_Line := Father.As_Subp_Body.F_Decls
.Sloc_Range.Start_Line + 1;
Text_Edit.Location.End_Line := Father.As_Subp_Body.F_Decls
.Sloc_Range.Start_Line + 1;
Generate_Text;
Text_Edit.Text := Define_Text;
else
Text_Edit.Location := Father.As_Expr_Function
.F_Expr.Children (1).Sloc_Range;
Generate_Text;
Text_Edit.Text := "(declare " & Define_Text & "begin "
& Text.Image
(Father.As_Expr_Function.F_Expr.Children (1).Text)
& ")";
end if;
return Text_Edit;
end Generate_Constant;
begin
for I_Param in Params'Range loop
if Param_Removable.Contains (Params (I_Param).P_Defining_Name) then
Last := I_Param;
Flag := True;
else
if Flag then
Indice_Range := (First, Last);
Param_Indices.Append (Indice_Range);
Flag := False;
end if;
First := I_Param + 1;
end if;
end loop;
if Flag then
Indice_Range := (First, Last);
Param_Indices.Append (Indice_Range);
end if;
if not Param_Indices.Is_Empty then
declare
Indice_Array : ReFac.Subprogram_Signature
.Parameter_Indices_Ranges_Type
(1 .. Param_Indices.Last_Index);
Edit_Info : ReFac.Text_Edit_Map;
begin
for I in 1 .. Param_Indices.Last_Index loop
Indice_Array (I) := Param_Indices (I);
end loop;
Edit_Info := ReFac.Subprogram_Signature.Remove_Parameter
.Remove_Parameters (Func_Name.P_Parent_Basic_Decl,
Indice_Array,
Unit_Array);
if Father.Kind not in LALCO.Ada_Subp_Decl_Range then
ReFac.Safe_Insert (Edit_Info, Func_Name.Unit.Get_Filename,
Generate_Constant);
end if;
Edit_Infos.Insert (Func_Name, Edit_Info);
end;
end if;
end Generate_Edits;
begin
for Unit of Unit_Array loop
Unit.Root.Traverse (Find_Subprogram'Access);
end loop;
for Subp_Name in Subpspec_To_Param.Iterate loop
-- Put_Line (Text.Image (Subp_Name.Key.Text));
-- for Param of Subpspec_To_Param (Subp_Name) loop
-- Put_Line (Text.Image (Param.Text));
-- end loop;
Generate_Edits (Subp_Name.Key);
end loop;
return (Edit_Infos, Subpspec_To_Param);
end Find_Dead_Param;
---------
-- Run --
---------
procedure Run
(Unit_Array : LAL.Analysis_Unit_Array;
Stream : in out VSS.Text_Streams.Output_Text_Stream'Class)
is
Edit_Info : Edit_Infos;
begin
Edit_Info := Find_Dead_Param (Unit_Array);
LAL_Refactor.Output.JSON_Serialize (Edit_Info, Stream);
end Run;
end LAL_Refactor.Tools.Suppress_Dead_Params_Tool;
|