Skip to content

Commit bb5146a

Browse files
committed
Swap If Not refactoring
For eng/ide/ada_language_server#1672 Depends-On: https://gitlab.adacore-it.com/eng/ide/lal-refactor/-/merge_requests/75
1 parent 94d490b commit bb5146a

File tree

5 files changed

+330
-0
lines changed

5 files changed

+330
-0
lines changed

doc/refactoring_tools.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
* [Replace Type](#replace-type)
2222
* [Auto Import](#auto-import)
2323
* [Sort Dependencies](#sort-dependencies)
24+
* [Swap If/else statments](#swap-if)
2425

2526
## Named Parameters
2627

@@ -247,3 +248,11 @@ See `src/lal_refactor-sort_dependencies.ads` in [LAL Refactor repository](https:
247248
Demo source is `sort_dependencies/` in [Code Samples](https://github.com/AdaCore/ada_language_server/blob/master/integration/vscode/Code%20Samples/refactoring_demos/).
248249

249250
![replace_type](media/replace_type.gif)
251+
252+
## Swap If/else statments
253+
254+
**Command name:** `als-refactor-swap_if_not`
255+
256+
* Swap If and else code branches and correct condition by adding/deleting `not`.
257+
258+
See `src/lal_refactor-swap_if_not` in [LAL Refactor repository](https://github.com/AdaCore/lal-refactor).

source/ada/lsp-ada_driver.adb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ with LSP.Ada_Handlers.Refactor.Replace_Type;
7979
with LSP.Ada_Handlers.Refactor.Sort_Case;
8080
with LSP.Ada_Handlers.Refactor.Sort_Dependencies;
8181
with LSP.Ada_Handlers.Refactor.Suppress_Seperate;
82+
with LSP.Ada_Handlers.Refactor.Swap_If_Not;
8283
with LSP.Ada_Handlers.Show_Dependencies_Commands;
8384
with LSP.Ada_Handlers.GPR_Dependencies_Commands;
8485
with LSP.Ada_Handlers.Source_Dirs_Commands;
@@ -237,6 +238,8 @@ procedure LSP.Ada_Driver is
237238
(LSP.Ada_Handlers.Refactor.Sort_Case.Declaration_Command'Tag);
238239
LSP.Ada_Commands.Register
239240
(LSP.Ada_Handlers.Refactor.Sort_Dependencies.Command'Tag);
241+
LSP.Ada_Commands.Register
242+
(LSP.Ada_Handlers.Refactor.Swap_If_Not.Command'Tag);
240243

241244
-- Refactoring - Change Subprogram Signature Commands
242245
LSP.Ada_Commands.Register
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
------------------------------------------------------------------------------
2+
-- Language Server Protocol --
3+
-- --
4+
-- Copyright (C) 2022-2023, AdaCore --
5+
-- --
6+
-- This is free software; you can redistribute it and/or modify it under --
7+
-- terms of the GNU General Public License as published by the Free Soft- --
8+
-- ware Foundation; either version 3, or (at your option) any later ver- --
9+
-- sion. This software is distributed in the hope that it will be useful, --
10+
-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- --
11+
-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public --
12+
-- License for more details. You should have received a copy of the GNU --
13+
-- General Public License distributed with this software; see file --
14+
-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy --
15+
-- of the license. --
16+
------------------------------------------------------------------------------
17+
18+
with Langkit_Support.Slocs; use Langkit_Support.Slocs;
19+
20+
with Libadalang.Analysis; use Libadalang.Analysis;
21+
22+
with LAL_Refactor; use LAL_Refactor;
23+
with LAL_Refactor.Swap_If_Not;
24+
use LAL_Refactor.Swap_If_Not;
25+
26+
with VSS.JSON.Streams;
27+
28+
with LSP.Enumerations;
29+
with LSP.Structures.LSPAny_Vectors; use LSP.Structures.LSPAny_Vectors;
30+
31+
package body LSP.Ada_Handlers.Refactor.Swap_If_Not is
32+
33+
pragma Warnings (Off);
34+
35+
----------------
36+
-- Initialize --
37+
----------------
38+
39+
procedure Initialize
40+
(Self : in out Command'Class;
41+
Context : LSP.Ada_Contexts.Context;
42+
Where : LSP.Structures.Location) is
43+
begin
44+
Self.Context_Id := Context.Id;
45+
Self.Location := Where;
46+
end Initialize;
47+
48+
------------------------
49+
-- Append_Code_Action --
50+
------------------------
51+
52+
procedure Append_Code_Action
53+
(Self : in out Command;
54+
Context : LSP.Ada_Context_Sets.Context_Access;
55+
Commands_Vector : in out LSP.Structures.Command_Or_CodeAction_Vector;
56+
Where : LSP.Structures.Location)
57+
is
58+
Code_Action : LSP.Structures.CodeAction;
59+
60+
begin
61+
Self.Initialize
62+
(Context => Context.all,
63+
Where => Where);
64+
65+
Code_Action :=
66+
(title => VSS.Strings.Conversions.To_Virtual_String (Self.Name),
67+
kind =>
68+
(Is_Set => True,
69+
Value => LSP.Enumerations.RefactorExtract),
70+
diagnostics => <>,
71+
edit => (Is_Set => False),
72+
isPreferred => (Is_Set => False),
73+
disabled => (Is_Set => False),
74+
command =>
75+
(Is_Set => True,
76+
Value =>
77+
(title => "",
78+
command => VSS.Strings.Conversions.To_Virtual_String
79+
(Command'External_Tag),
80+
arguments => Self.Write_Command)),
81+
data => <>);
82+
83+
Commands_Vector.Append
84+
(LSP.Structures.Command_Or_CodeAction'
85+
(Is_Command => False, CodeAction => Code_Action));
86+
end Append_Code_Action;
87+
88+
------------
89+
-- Create --
90+
------------
91+
92+
overriding function Create
93+
(Any : not null access LSP.Structures.LSPAny_Vector)
94+
return Command
95+
is
96+
use VSS.JSON.Streams;
97+
use VSS.Strings;
98+
use LSP.Structures.JSON_Event_Vectors;
99+
100+
C : Cursor := Any.First;
101+
begin
102+
return Self : Command do
103+
pragma Assert (Element (C).Kind = Start_Array);
104+
Next (C);
105+
pragma Assert (Element (C).Kind = Start_Object);
106+
Next (C);
107+
108+
while Has_Element (C)
109+
and then Element (C).Kind /= End_Object
110+
loop
111+
pragma Assert (Element (C).Kind = Key_Name);
112+
declare
113+
Key : constant Virtual_String := Element (C).Key_Name;
114+
begin
115+
Next (C);
116+
117+
if Key = "context_id" then
118+
Self.Context_Id := Element (C).String_Value;
119+
120+
elsif Key = "location" then
121+
Self.Location := From_Any (C);
122+
123+
else
124+
Skip_Value (C);
125+
end if;
126+
end;
127+
128+
Next (C);
129+
end loop;
130+
end return;
131+
end Create;
132+
133+
--------------
134+
-- Refactor --
135+
--------------
136+
137+
overriding procedure Refactor
138+
(Self : Command;
139+
Handler : not null access LSP.Ada_Handlers.Message_Handler'Class;
140+
Edits : out LAL_Refactor.Refactoring_Edits)
141+
is
142+
Message_Handler : LSP.Ada_Handlers.Message_Handler renames
143+
LSP.Ada_Handlers.Message_Handler (Handler.all);
144+
Context : LSP.Ada_Contexts.Context renames
145+
Message_Handler.Contexts.Get (Self.Context_Id).all;
146+
147+
function Analysis_Units return Analysis_Unit_Array is
148+
(Context.Analysis_Units);
149+
-- Provides the Context Analysis_Unit_Array to the Mode_Changer
150+
151+
File : constant GNATCOLL.VFS.Virtual_File :=
152+
Message_Handler.To_File (Self.Location.uri);
153+
154+
Unit : constant Analysis_Unit := Context.Get_AU (File);
155+
Location : constant Source_Location :=
156+
(Langkit_Support.Slocs.Line_Number
157+
(Self.Location.a_range.start.line) + 1,
158+
Column_Number
159+
(Self.Location.a_range.start.character) + 1);
160+
161+
Swap : constant Swaper :=
162+
Create_Swaper
163+
(Unit => Unit,
164+
Location => Location);
165+
begin
166+
Edits := Swap.Refactor (Analysis_Units'Access);
167+
end Refactor;
168+
169+
-------------------
170+
-- Write_Command --
171+
-------------------
172+
173+
function Write_Command
174+
(Self : Command) return LSP.Structures.LSPAny_Vector
175+
is
176+
use VSS.JSON.Streams;
177+
178+
Result : LSP.Structures.LSPAny_Vector;
179+
begin
180+
Result.Append (JSON_Stream_Element'(Kind => Start_Array));
181+
Result.Append (JSON_Stream_Element'(Kind => Start_Object));
182+
183+
-- "context_id"
184+
Add_Key ("context_id", Result);
185+
To_Any (Self.Context_Id, Result);
186+
187+
-- "section_to_extract_sloc"
188+
Add_Key ("location", Result);
189+
To_Any (Self.Location, Result);
190+
191+
Result.Append (JSON_Stream_Element'(Kind => End_Object));
192+
Result.Append (JSON_Stream_Element'(Kind => End_Array));
193+
194+
return Result;
195+
end Write_Command;
196+
197+
end LSP.Ada_Handlers.Refactor.Swap_If_Not;
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
------------------------------------------------------------------------------
2+
-- Language Server Protocol --
3+
-- --
4+
-- Copyright (C) 2025, AdaCore --
5+
-- --
6+
-- This is free software; you can redistribute it and/or modify it under --
7+
-- terms of the GNU General Public License as published by the Free Soft- --
8+
-- ware Foundation; either version 3, or (at your option) any later ver- --
9+
-- sion. This software is distributed in the hope that it will be useful, --
10+
-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- --
11+
-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public --
12+
-- License for more details. You should have received a copy of the GNU --
13+
-- General Public License distributed with this software; see file --
14+
-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy --
15+
-- of the license. --
16+
------------------------------------------------------------------------------
17+
--
18+
-- Implementation of the refactoring command to extract variable
19+
20+
with VSS.Strings;
21+
22+
with LSP.Ada_Contexts;
23+
with LSP.Server_Jobs;
24+
25+
package LSP.Ada_Handlers.Refactor.Swap_If_Not is
26+
27+
type Command is new LSP.Ada_Handlers.Refactor.Command with private;
28+
29+
overriding function Name (Self : Command) return String
30+
is ("Swap If Not");
31+
32+
procedure Append_Code_Action
33+
(Self : in out Command;
34+
Context : LSP.Ada_Context_Sets.Context_Access;
35+
Commands_Vector : in out LSP.Structures.Command_Or_CodeAction_Vector;
36+
Where : LSP.Structures.Location);
37+
-- Initializes Self and appends it to Commands_Vector
38+
39+
private
40+
41+
type Command is new LSP.Ada_Handlers.Refactor.Command with record
42+
Context_Id : VSS.Strings.Virtual_String;
43+
Location : LSP.Structures.Location;
44+
end record;
45+
46+
overriding
47+
function Create
48+
(Any : not null access LSP.Structures.LSPAny_Vector)
49+
return Command;
50+
-- Reads Any and creates a new Command
51+
52+
overriding
53+
procedure Refactor
54+
(Self : Command;
55+
Handler : not null access LSP.Ada_Handlers.Message_Handler'Class;
56+
Edits : out LAL_Refactor.Refactoring_Edits);
57+
-- Executes Self by computing the necessary refactorings
58+
59+
overriding function Priority (Self : Command)
60+
return LSP.Server_Jobs.Job_Priority
61+
is (LSP.Server_Jobs.Low);
62+
63+
procedure Initialize
64+
(Self : in out Command'Class;
65+
Context : LSP.Ada_Contexts.Context;
66+
Where : LSP.Structures.Location);
67+
-- Initializes Self
68+
69+
function Write_Command
70+
(Self : Command) return LSP.Structures.LSPAny_Vector;
71+
72+
for Command'External_Tag use "als-refactor-swap_if_not";
73+
74+
end LSP.Ada_Handlers.Refactor.Swap_If_Not;

source/ada/lsp-ada_handlers.adb

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ with LAL_Refactor.Subprogram_Signature.Change_Parameters_Default_Value;
4848
with LAL_Refactor.Subprogram_Signature.Change_Parameters_Type;
4949
with LAL_Refactor.Subprogram_Signature.Remove_Parameter;
5050
with LAL_Refactor.Suppress_Separate;
51+
with LAL_Refactor.Swap_If_Not;
5152

5253
with LSP.Ada_Completions.Aspects;
5354
with LSP.Ada_Completions.Attributes;
@@ -84,6 +85,7 @@ with LSP.Ada_Handlers.Refactor.Replace_Type;
8485
with LSP.Ada_Handlers.Refactor.Sort_Case;
8586
with LSP.Ada_Handlers.Refactor.Sort_Dependencies;
8687
with LSP.Ada_Handlers.Refactor.Suppress_Seperate;
88+
with LSP.Ada_Handlers.Refactor.Swap_If_Not;
8789
with LSP.Ada_Handlers.Renaming;
8890
with LSP.Ada_Handlers.Symbols;
8991
with LSP.Ada_Commands;
@@ -779,6 +781,10 @@ package body LSP.Ada_Handlers is
779781
-- Checks if the Sort Dependencies refactoring tool is available,
780782
-- and if so, appends a Code Action with its Command.
781783

784+
procedure Swap_If_Not_Code_Action;
785+
-- Checks if the Swap_If_Not refactoring tool is available,
786+
-- and if so, appends a Code Action with its Command.
787+
782788
-------------------------------------------------
783789
-- Change_Parameters_Default_Value_Code_Action --
784790
-------------------------------------------------
@@ -1324,6 +1330,45 @@ package body LSP.Ada_Handlers is
13241330
end if;
13251331
end Sort_Dependencies_Code_Action;
13261332

1333+
-----------------------------
1334+
-- Swap_If_Not_Code_Action --
1335+
-----------------------------
1336+
1337+
procedure Swap_If_Not_Code_Action is
1338+
use LSP.Ada_Handlers.Refactor.Swap_If_Not;
1339+
use Langkit_Support.Slocs;
1340+
use LAL_Refactor.Swap_If_Not;
1341+
use type LSP.Structures.Position;
1342+
1343+
Single_Location : constant Boolean :=
1344+
Value.a_range.start = Value.a_range.an_end;
1345+
1346+
Location : Source_Location :=
1347+
(Langkit_Support.Slocs.Line_Number
1348+
(Value.a_range.start.line) + 1,
1349+
Column_Number (Value.a_range.start.character) + 1);
1350+
1351+
Swap_Command : Command;
1352+
1353+
begin
1354+
if Single_Location
1355+
and then Is_Swap_Available (Node.Unit, Location)
1356+
then
1357+
Swap_Command.Append_Code_Action
1358+
(Context => Context,
1359+
Commands_Vector => Result,
1360+
Where =>
1361+
(Value.textDocument.uri,
1362+
((Natural (Location.Line) - 1,
1363+
Natural (Location.Column) - 1),
1364+
(Natural (Location.Line) - 1,
1365+
Natural (Location.Column) - 1)),
1366+
LSP.Constants.Empty));
1367+
1368+
Found := True;
1369+
end if;
1370+
end Swap_If_Not_Code_Action;
1371+
13271372
begin
13281373
Named_Parameters_Code_Action;
13291374

@@ -1521,6 +1566,8 @@ package body LSP.Ada_Handlers is
15211566
if Self.Client.Refactoring_Replace_Type then
15221567
Replace_Type_Code_Action;
15231568
end if;
1569+
1570+
Swap_If_Not_Code_Action;
15241571
end Analyse_Node;
15251572

15261573
----------------------------------

0 commit comments

Comments
 (0)