Skip to content

Commit 79f260d

Browse files
author
Vivek Mathur
committed
Merge branch 'refactor/32/codegen' into 'master'
Add CodeAction for Generate Subprogram refactoring See merge request eng/ide/ada_language_server!2162
2 parents 33f1388 + 3dca80d commit 79f260d

20 files changed

+1131
-16
lines changed

source/ada/lsp-ada_completions-keywords.adb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ package body LSP.Ada_Completions.Keywords is
4040
Result : in out LSP.Structures.CompletionList)
4141
is
4242
pragma Unreferenced (Names);
43-
Prev : constant Libadalang.Common.Token_Reference :=
43+
Prev : constant Libadalang.Common.Token_Reference :=
4444
Libadalang.Common.Previous (Token);
4545

4646
begin

source/ada/lsp-ada_completions.ads

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ package LSP.Ada_Completions is
9494
-- Example: abc|; or abc|<space>
9595
-- Cursor: ^ ^
9696
-- Consider `abc;` or `abc<space>` and Sloc is a character after `c`, then
97-
-- Token is `abc`, because a user expect it to te completed.
97+
-- Token is `abc`, because a user expects it to be completed.
9898
-- The Node is immediate enclosing AST node for the token.
9999
-- The Filter could be used to quick check common completion contexts.
100100

source/ada/lsp-ada_driver.adb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ with LSP.Ada_Handlers.Refactor.Change_Parameters_Type;
7070
with LSP.Ada_Handlers.Refactor.Delete_Entity;
7171
with LSP.Ada_Handlers.Refactor.Extract_Subprogram;
7272
with LSP.Ada_Handlers.Refactor.Extract_Variable;
73+
with LSP.Ada_Handlers.Refactor.Generate_Subprogram;
7374
with LSP.Ada_Handlers.Refactor.Inline_Variable;
7475
with LSP.Ada_Handlers.Refactor.Introduce_Parameter;
7576
with LSP.Ada_Handlers.Refactor.Move_Parameter;
@@ -232,6 +233,8 @@ procedure LSP.Ada_Driver is
232233
(LSP.Ada_Handlers.Refactor.Extract_Subprogram.Command'Tag);
233234
LSP.Ada_Commands.Register
234235
(LSP.Ada_Handlers.Refactor.Extract_Variable.Command'Tag);
236+
LSP.Ada_Commands.Register
237+
(LSP.Ada_Handlers.Refactor.Generate_Subprogram.Command'Tag);
235238
LSP.Ada_Commands.Register
236239
(LSP.Ada_Handlers.Refactor.Inline_Variable.Command'Tag);
237240
LSP.Ada_Commands.Register

source/ada/lsp-ada_handlers-refactor-extract_subprogram.ads

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
-- of the license. --
1616
------------------------------------------------------------------------------
1717
--
18-
-- Implementation of the refactoring command to add parameters
18+
-- Implementation of the refactoring command to extract subprograms
1919

2020
with Libadalang.Common;
2121

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
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+
with Langkit_Support.Slocs; use Langkit_Support.Slocs;
19+
20+
with Libadalang.Analysis; use Libadalang.Analysis;
21+
with Libadalang.Common; use Libadalang.Common;
22+
23+
with LAL_Refactor; use LAL_Refactor;
24+
with LAL_Refactor.Generate_Subprogram;
25+
26+
with LSP.Structures;
27+
with VSS.JSON.Streams;
28+
with VSS.Strings.Conversions;
29+
with LSP.Enumerations;
30+
with LSP.Structures.LSPAny_Vectors; use LSP.Structures.LSPAny_Vectors;
31+
32+
package body LSP.Ada_Handlers.Refactor.Generate_Subprogram is
33+
34+
------------------------
35+
-- Append_Code_Action --
36+
------------------------
37+
38+
procedure Append_Code_Action
39+
(Self : in out Command;
40+
Context : LSP.Ada_Context_Sets.Context_Access;
41+
Commands_Vector : in out LSP.Structures.Command_Or_CodeAction_Vector;
42+
Subp_Start : LSP.Structures.Location;
43+
Subp_Type : Ada_Subp_Kind)
44+
is
45+
Code_Action : LSP.Structures.CodeAction;
46+
47+
Code_Action_Title : constant String :=
48+
(if Subp_Type in Ada_Subp_Kind_Procedure_Range
49+
then "Generate Procedure Body"
50+
else "Generate Function Body");
51+
52+
begin
53+
Self.Initialize (Context => Context.all, Subp_Start => Subp_Start);
54+
55+
Code_Action :=
56+
(title =>
57+
VSS.Strings.Conversions.To_Virtual_String (Code_Action_Title),
58+
kind =>
59+
(Is_Set => True, Value => LSP.Enumerations.RefactorRewrite),
60+
diagnostics => <>,
61+
edit => (Is_Set => False),
62+
isPreferred => (Is_Set => False),
63+
disabled => (Is_Set => False),
64+
command =>
65+
(Is_Set => True,
66+
Value =>
67+
(title => "",
68+
command =>
69+
VSS.Strings.Conversions.To_Virtual_String
70+
(Command'External_Tag),
71+
arguments => Self.Write_Command)),
72+
data => <>);
73+
74+
Commands_Vector.Append
75+
(LSP.Structures.Command_Or_CodeAction'
76+
(Is_Command => False, CodeAction => Code_Action));
77+
end Append_Code_Action;
78+
79+
------------
80+
-- Create --
81+
------------
82+
83+
overriding
84+
function Create
85+
(Any : not null access LSP.Structures.LSPAny_Vector) return Command
86+
is
87+
use VSS.JSON.Streams;
88+
use VSS.Strings;
89+
use LSP.Structures.JSON_Event_Vectors;
90+
91+
C : Cursor := Any.First;
92+
begin
93+
return Self : Command do
94+
pragma Assert (Element (C).Kind = Start_Array);
95+
Next (C);
96+
pragma Assert (Element (C).Kind = Start_Object);
97+
Next (C);
98+
99+
while Has_Element (C) and then Element (C).Kind /= End_Object loop
100+
pragma Assert (Element (C).Kind = Key_Name);
101+
declare
102+
Key : constant Virtual_String := Element (C).Key_Name;
103+
begin
104+
Next (C);
105+
106+
if Key = "context_id" then
107+
Self.Context_Id := Element (C).String_Value;
108+
109+
elsif Key = "subp_start" then
110+
Self.Subp_Start := From_Any (C);
111+
112+
else
113+
Skip_Value (C);
114+
end if;
115+
end;
116+
117+
Next (C);
118+
end loop;
119+
end return;
120+
end Create;
121+
122+
--------------
123+
-- Refactor --
124+
--------------
125+
126+
overriding
127+
procedure Refactor
128+
(Self : Command;
129+
Handler : not null access LSP.Ada_Handlers.Message_Handler'Class;
130+
Edits : out LAL_Refactor.Refactoring_Edits)
131+
is
132+
use LAL_Refactor.Generate_Subprogram;
133+
134+
Message_Handler : LSP.Ada_Handlers.Message_Handler renames
135+
LSP.Ada_Handlers.Message_Handler (Handler.all);
136+
Context : LSP.Ada_Contexts.Context renames
137+
Message_Handler.Contexts.Get (Self.Context_Id).all;
138+
File : constant GNATCOLL.VFS.Virtual_File :=
139+
Message_Handler.To_File (Self.Subp_Start.uri);
140+
Dest_Filename : constant String := File.Display_Full_Name;
141+
Document : LSP.Ada_Documents.Document_Access;
142+
Node : Ada_Node := No_Ada_Node;
143+
Target_Subp : Subp_Decl := No_Subp_Decl;
144+
-- As Node is retrieved from the Decl SLOC_Range, we assume Node is
145+
-- a direct child of the Subp_Decl, otherwise Get_Subp_Decl fails
146+
147+
function Analysis_Units return Analysis_Unit_Array
148+
is (Context.Analysis_Units);
149+
-- Provide project context for refactor engine
150+
begin
151+
Document := Message_Handler.Get_Open_Document (Self.Subp_Start.uri);
152+
Node := Document.Get_Node_At (Context, Self.Subp_Start.a_range.start);
153+
Target_Subp := Get_Subp_Decl (Node);
154+
if Target_Subp.Is_Null then
155+
Edits.Diagnostics.Append
156+
(New_Item =>
157+
Report_Error
158+
("The target subprogram could not be resolved precisely.",
159+
Node));
160+
else
161+
Edits :=
162+
Create_Subprogram_Generator (Target_Subp, Dest_Filename).Refactor
163+
(Analysis_Units'Access);
164+
end if;
165+
exception
166+
when E : others =>
167+
Message_Handler.Trace_Exception
168+
(E,
169+
VSS.Strings.Conversions.To_Virtual_String
170+
("Failed to retrieve document or node from LSP range."));
171+
Edits.Diagnostics.Append
172+
(New_Item =>
173+
Report_Error
174+
(Msg => "The target subprogram could not be resolved precisely.",
175+
SLOC =>
176+
Message_Handler.From_LSP_Range
177+
(Context.Get_AU (File), Self.Subp_Start.a_range),
178+
File => Dest_Filename));
179+
Document.Cleanup;
180+
end Refactor;
181+
182+
----------------
183+
-- Initialize --
184+
----------------
185+
186+
procedure Initialize
187+
(Self : in out Command'Class;
188+
Context : LSP.Ada_Contexts.Context;
189+
Subp_Start : LSP.Structures.Location) is
190+
begin
191+
Self.Context_Id := Context.Id;
192+
Self.Subp_Start := Subp_Start;
193+
end Initialize;
194+
195+
-------------------
196+
-- Write_Command --
197+
-------------------
198+
199+
function Write_Command (Self : Command) return LSP.Structures.LSPAny_Vector
200+
is
201+
use VSS.JSON.Streams;
202+
203+
Result : LSP.Structures.LSPAny_Vector;
204+
begin
205+
Result.Append (JSON_Stream_Element'(Kind => Start_Array));
206+
Result.Append (JSON_Stream_Element'(Kind => Start_Object));
207+
208+
-- "context_id"
209+
Add_Key ("context_id", Result);
210+
To_Any (Self.Context_Id, Result);
211+
212+
-- "subp_start"
213+
Add_Key ("subp_start", Result);
214+
To_Any (Self.Subp_Start, Result);
215+
216+
Result.Append (JSON_Stream_Element'(Kind => End_Object));
217+
Result.Append (JSON_Stream_Element'(Kind => End_Array));
218+
219+
return Result;
220+
end Write_Command;
221+
222+
end LSP.Ada_Handlers.Refactor.Generate_Subprogram;
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 generate subprogram stubs
19+
20+
with VSS.Strings;
21+
with Libadalang.Common;
22+
with LSP.Ada_Contexts;
23+
with LSP.Server_Jobs;
24+
25+
package LSP.Ada_Handlers.Refactor.Generate_Subprogram is
26+
27+
type Command is new LSP.Ada_Handlers.Refactor.Command with private;
28+
29+
overriding
30+
function Name (Self : Command) return String
31+
is ("Generate Subprogram Body");
32+
33+
procedure Append_Code_Action
34+
(Self : in out Command;
35+
Context : LSP.Ada_Context_Sets.Context_Access;
36+
Commands_Vector : in out LSP.Structures.Command_Or_CodeAction_Vector;
37+
Subp_Start : LSP.Structures.Location;
38+
Subp_Type : Libadalang.Common.Ada_Subp_Kind);
39+
-- Initializes Self and appends it to Commands_Vector
40+
41+
private
42+
43+
type Command is new LSP.Ada_Handlers.Refactor.Command with record
44+
Context_Id : VSS.Strings.Virtual_String;
45+
Subp_Start : LSP.Structures.Location;
46+
end record;
47+
48+
overriding
49+
function Create
50+
(Any : not null access LSP.Structures.LSPAny_Vector) return Command;
51+
-- Reads Any and creates a new Command
52+
53+
overriding
54+
procedure Refactor
55+
(Self : Command;
56+
Handler : not null access LSP.Ada_Handlers.Message_Handler'Class;
57+
Edits : out LAL_Refactor.Refactoring_Edits);
58+
-- Executes Self by computing the necessary refactorings
59+
60+
overriding
61+
function Priority (Self : Command) return LSP.Server_Jobs.Job_Priority
62+
is (LSP.Server_Jobs.Low);
63+
64+
procedure Initialize
65+
(Self : in out Command'Class;
66+
Context : LSP.Ada_Contexts.Context;
67+
Subp_Start : LSP.Structures.Location);
68+
-- Initializes Self
69+
70+
function Write_Command (Self : Command) return LSP.Structures.LSPAny_Vector;
71+
72+
for Command'External_Tag use "als-refactor-generate-subprogram-body";
73+
74+
end LSP.Ada_Handlers.Refactor.Generate_Subprogram;

0 commit comments

Comments
 (0)